Initial commit: added first config

master
Mark 2022-02-06 12:00:50 -08:00
commit 8c9f293840
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
15 changed files with 2665 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.gch

487
betalupi_ergodox.c Normal file
View File

@ -0,0 +1,487 @@
/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
Copyright 2015 ZSA Technology Labs Inc (@zsa)
Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
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 "betalupi_ergodox.h"
extern inline void ergodox_board_led_on(void);
extern inline void ergodox_right_led_1_on(void);
extern inline void ergodox_right_led_2_on(void);
extern inline void ergodox_right_led_3_on(void);
extern inline void ergodox_right_led_on(uint8_t led);
extern inline void ergodox_board_led_off(void);
extern inline void ergodox_right_led_1_off(void);
extern inline void ergodox_right_led_2_off(void);
extern inline void ergodox_right_led_3_off(void);
extern inline void ergodox_right_led_off(uint8_t led);
extern inline void ergodox_led_all_on(void);
extern inline void ergodox_led_all_off(void);
extern inline void ergodox_right_led_1_set(uint8_t n);
extern inline void ergodox_right_led_2_set(uint8_t n);
extern inline void ergodox_right_led_3_set(uint8_t n);
extern inline void ergodox_right_led_set(uint8_t led, uint8_t n);
extern inline void ergodox_led_all_set(uint8_t n);
keyboard_config_t keyboard_config;
bool i2c_initialized = 0;
i2c_status_t mcp23018_status = 0x20;
void matrix_init_kb(void) {
// keyboard LEDs (see "PWM on ports OC1(A|B|C)" in "teensy-2-0.md")
TCCR1A = 0b10101001; // set and configure fast PWM
TCCR1B = 0b00001001; // set and configure fast PWM
// (tied to Vcc for hardware convenience)
DDRB &= ~(1<<4); // set B(4) as input
PORTB &= ~(1<<4); // set B(4) internal pull-up disabled
// unused pins - C7, D4, D5, D7, E6
// set as input with internal pull-up enabled
DDRC &= ~(1<<7);
DDRD &= ~(1<<5 | 1<<4);
DDRE &= ~(1<<6);
PORTC |= (1<<7);
PORTD |= (1<<5 | 1<<4);
PORTE |= (1<<6);
keyboard_config.raw = eeconfig_read_kb();
ergodox_led_all_set((uint8_t)keyboard_config.led_level * 255 / 4 );
#ifdef RGB_MATRIX_ENABLE
if (keyboard_config.rgb_matrix_enable) {
rgb_matrix_set_flags(LED_FLAG_ALL);
} else {
rgb_matrix_set_flags(LED_FLAG_NONE);
}
#endif
ergodox_blink_all_leds();
matrix_init_user();
}
void ergodox_blink_all_leds(void)
{
ergodox_led_all_off();
ergodox_led_all_set(LED_BRIGHTNESS_DEFAULT);
ergodox_right_led_1_on();
_delay_ms(50);
ergodox_right_led_2_on();
_delay_ms(50);
ergodox_right_led_3_on();
_delay_ms(50);
#ifdef LEFT_LEDS
ergodox_left_led_1_on();
_delay_ms(50);
if (!mcp23018_status) {
mcp23018_status = ergodox_left_leds_update();
}
ergodox_left_led_2_on();
_delay_ms(50);
if (!mcp23018_status) {
mcp23018_status = ergodox_left_leds_update();
}
ergodox_left_led_3_on();
_delay_ms(50);
if (!mcp23018_status) {
mcp23018_status = ergodox_left_leds_update();
}
#endif
ergodox_right_led_1_off();
_delay_ms(50);
ergodox_right_led_2_off();
_delay_ms(50);
ergodox_right_led_3_off();
#ifdef LEFT_LEDS
_delay_ms(50);
ergodox_left_led_1_off();
if (!mcp23018_status) {
mcp23018_status = ergodox_left_leds_update();
}
_delay_ms(50);
ergodox_left_led_2_off();
if (!mcp23018_status) {
mcp23018_status = ergodox_left_leds_update();
}
_delay_ms(50);
ergodox_left_led_3_off();
if (!mcp23018_status) {
mcp23018_status = ergodox_left_leds_update();
}
#endif
//ergodox_led_all_on();
//_delay_ms(333);
ergodox_led_all_set((uint8_t)keyboard_config.led_level * 255 / 4 );
ergodox_led_all_off();
}
uint8_t init_mcp23018(void) {
mcp23018_status = 0x20;
// I2C subsystem
// uint8_t sreg_prev;
// sreg_prev=SREG;
// cli();
if (i2c_initialized == 0) {
i2c_init(); // on pins D(1,0)
i2c_initialized = true;
_delay_ms(1000);
}
// i2c_init(); // on pins D(1,0)
// _delay_ms(1000);
// set pin direction
// - unused : input : 1
// - input : input : 1
// - driving : output : 0
mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(IODIRA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b00000000, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b00111111, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
i2c_stop();
// set pull-up
// - unused : on : 1
// - input : on : 1
// - driving : off : 0
mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(GPPUA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b00000000, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b00111111, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
out:
i2c_stop();
#ifdef LEFT_LEDS
if (!mcp23018_status) mcp23018_status = ergodox_left_leds_update();
#endif // LEFT_LEDS
// SREG=sreg_prev;
return mcp23018_status;
}
#ifdef LEFT_LEDS
uint8_t ergodox_left_leds_update(void) {
if (mcp23018_status) { // if there was an error
return mcp23018_status;
}
#define LEFT_LED_1_SHIFT 7 // in MCP23018 port B
#define LEFT_LED_2_SHIFT 6 // in MCP23018 port B
#define LEFT_LED_3_SHIFT 7 // in MCP23018 port A
// set logical value (doesn't matter on inputs)
// - unused : hi-Z : 1
// - input : hi-Z : 1
// - driving : hi-Z : 1
mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
if (mcp23018_status) goto out;
mcp23018_status = i2c_write(OLATA, ERGODOX_EZ_I2C_TIMEOUT);
if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b11111111
& ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT),
ERGODOX_EZ_I2C_TIMEOUT);
if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b11111111
& ~(ergodox_left_led_2<<LEFT_LED_2_SHIFT)
& ~(ergodox_left_led_1<<LEFT_LED_1_SHIFT),
ERGODOX_EZ_I2C_TIMEOUT);
if (mcp23018_status) goto out;
out:
i2c_stop();
return mcp23018_status;
}
#endif
#ifdef SWAP_HANDS_ENABLE
__attribute__ ((weak))
// swap-hands action needs a matrix to define the swap
const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
/* Left hand, matrix positions */
{{0,13}, {1,13}, {2,13}, {3,13}, {4,13}, {5,13}},
{{0,12}, {1,12}, {2,12}, {3,12}, {4,12}, {5,12}},
{{0,11}, {1,11}, {2,11}, {3,11}, {4,11}, {5,11}},
{{0,10}, {1,10}, {2,10}, {3,10}, {4,10}, {5,10}},
{{0,9}, {1,9}, {2,9}, {3,9}, {4,9}, {5,9}},
{{0,8}, {1,8}, {2,8}, {3,8}, {4,8}, {5,8}},
{{0,7}, {1,7}, {2,7}, {3,7}, {4,7}, {5,7}},
/* Right hand, matrix positions */
{{0,6}, {1,6}, {2,6}, {3,6}, {4,6}, {5,6}},
{{0,5}, {1,5}, {2,5}, {3,5}, {4,5}, {5,5}},
{{0,4}, {1,4}, {2,4}, {3,4}, {4,4}, {5,4}},
{{0,3}, {1,3}, {2,3}, {3,3}, {4,3}, {5,3}},
{{0,2}, {1,2}, {2,2}, {3,2}, {4,2}, {5,2}},
{{0,1}, {1,1}, {2,1}, {3,1}, {4,1}, {5,1}},
{{0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {5,0}},
};
#endif
#ifdef RGB_MATRIX_ENABLE
void suspend_power_down_kb(void) {
rgb_matrix_set_suspend_state(true);
suspend_power_down_user();
}
void suspend_wakeup_init_kb(void) {
rgb_matrix_set_suspend_state(false);
suspend_wakeup_init_user();
}
const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
/* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, C3_1, C2_1, C4_1}, // LED1 on right
{0, C6_1, C5_1, C7_1}, // LED2
{0, C4_2, C3_2, C5_2}, // LED3
{0, C7_2, C6_2, C8_2}, // LED4
{0, C2_3, C1_3, C3_3}, // LED5
{0, C5_3, C4_3, C6_3}, // LED6
{0, C8_3, C7_3, C9_3}, // LED7
{0, C2_4, C1_4, C3_4}, // LED8
{0, C6_4, C5_4, C7_4}, // LED9
{0, C2_5, C1_5, C3_5}, // LED10
{0, C7_5, C6_5, C8_5}, // LED11
{0, C2_6, C1_6, C3_6}, // LED12
{0, C5_6, C4_6, C6_6}, // LED13
{0, C8_6, C7_6, C9_6}, // LED14
{0, C2_7, C1_7, C3_7}, // LED15
{0, C5_7, C4_7, C6_7}, // LED16
{0, C2_8, C1_8, C3_8}, // LED17
{0, C5_8, C4_8, C6_8}, // LED18
{0, C3_9, C2_9, C4_9}, // LED19
{0, C6_9, C5_9, C7_9}, // LED20
{0, C4_10, C3_10, C5_10}, // LED21
{0, C7_10, C6_10, C8_10}, // LED22
{0, C2_11, C1_11, C3_11}, // LED23
{0, C5_11, C4_11, C6_11}, // LED24
{1, C3_1, C2_1, C4_1}, // LED1 on left
{1, C6_1, C5_1, C7_1}, // LED2
{1, C4_2, C3_2, C5_2}, // LED3
{1, C7_2, C6_2, C8_2}, // LED4
{1, C2_3, C1_3, C3_3}, // LED5
{1, C5_3, C4_3, C6_3}, // LED6
{1, C8_3, C7_3, C9_3}, // LED7
{1, C2_4, C1_4, C3_4}, // LED8
{1, C6_4, C5_4, C7_4}, // LED9
{1, C2_5, C1_5, C3_5}, // LED10
{1, C7_5, C6_5, C8_5}, // LED11
{1, C2_6, C1_6, C3_6}, // LED12
{1, C5_6, C4_6, C6_6}, // LED13
{1, C8_6, C7_6, C9_6}, // LED14
{1, C2_7, C1_7, C3_7}, // LED15
{1, C5_7, C4_7, C6_7}, // LED16
{1, C2_8, C1_8, C3_8}, // LED17
{1, C5_8, C4_8, C6_8}, // LED18
{1, C3_9, C2_9, C4_9}, // LED19
{1, C6_9, C5_9, C7_9}, // LED20
{1, C4_10, C3_10, C5_10}, // LED21
{1, C7_10, C6_10, C8_10}, // LED22
{1, C2_11, C1_11, C3_11}, // LED23
{1, C5_11, C4_11, C6_11} // LED24
};
led_config_t g_led_config = { {
{ NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
{ 28, 33, 38, 43, 47, NO_LED },
{ 27, 32, 37, 42, 46, NO_LED },
{ 26, 31, 36, 41, 45, NO_LED },
{ 25, 30, 35, 40, 44, NO_LED },
{ 24, 29, 34, 39, NO_LED, NO_LED },
{ NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
{ NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
{ 0, 5, 10, 15, NO_LED, NO_LED },
{ 1, 6, 11, 16, 20, NO_LED },
{ 2, 7, 12, 17, 21, NO_LED },
{ 3, 8, 13, 18, 22, NO_LED },
{ 4, 9, 14, 19, 23, NO_LED },
{ NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED }
}, {
{ 137, 0 }, { 154, 0 }, { 172, 0 }, { 189, 0 }, { 206, 0 }, { 137, 12 },
{ 154, 12 }, { 172, 12 }, { 189, 12 }, { 206, 12 }, { 137, 25 }, { 154, 25 },
{ 172, 25 }, { 189, 25 }, { 206, 25 }, { 137, 38 }, { 154, 38 }, { 172, 38 },
{ 189, 38 }, { 206, 38 }, { 154, 51 }, { 172, 51 }, { 189, 51 }, { 206, 51 },
{ 86, 0 }, { 68, 0 }, { 51, 0 }, { 34, 0 }, { 17, 0 }, { 86, 12 },
{ 68, 12 }, { 51, 12 }, { 34, 12 }, { 17, 12 }, { 86, 25 }, { 68, 25 },
{ 51, 25 }, { 34, 25 }, { 17, 25 }, { 86, 38 }, { 68, 38 }, { 51, 38 },
{ 34, 38 }, { 17, 38 }, { 68, 51 }, { 51, 51 }, { 34, 51 }, { 17, 51 }
}, {
4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4,
4, 4, 1, 1, 1, 1,
4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4,
4, 4, 1, 1, 1, 1
} };
void keyboard_post_init_kb(void) {
rgb_matrix_enable_noeeprom();
keyboard_post_init_user();
}
#endif
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case LED_LEVEL:
if (record->event.pressed) {
keyboard_config.led_level++;
if (keyboard_config.led_level > 4) {
keyboard_config.led_level = 0;
}
ergodox_led_all_set((uint8_t)keyboard_config.led_level * 255 / 4 );
eeconfig_update_kb(keyboard_config.raw);
layer_state_set_kb(layer_state);
}
break;
#ifdef RGB_MATRIX_ENABLE
case TOGGLE_LAYER_COLOR:
if (record->event.pressed) {
keyboard_config.disable_layer_led ^= 1;
if (keyboard_config.disable_layer_led)
rgb_matrix_set_color_all(0, 0, 0);
eeconfig_update_kb(keyboard_config.raw);
}
break;
case RGB_TOG:
if (record->event.pressed) {
switch (rgb_matrix_get_flags()) {
case LED_FLAG_ALL: {
rgb_matrix_set_flags(LED_FLAG_NONE);
keyboard_config.rgb_matrix_enable = false;
rgb_matrix_set_color_all(0, 0, 0);
}
break;
default: {
rgb_matrix_set_flags(LED_FLAG_ALL);
keyboard_config.rgb_matrix_enable = true;
}
break;
}
eeconfig_update_kb(keyboard_config.raw);
}
return false;
#endif
}
return process_record_user(keycode, record);
}
void eeconfig_init_kb(void) { // EEPROM is getting reset!
keyboard_config.raw = 0;
keyboard_config.led_level = 4;
keyboard_config.rgb_matrix_enable = true;
eeconfig_update_kb(keyboard_config.raw);
eeconfig_init_user();
}
#ifdef ORYX_ENABLE
static uint16_t loops = 0;
static bool is_on = false;
#endif
#ifdef DYNAMIC_MACRO_ENABLE
static bool is_dynamic_recording = false;
static uint16_t dynamic_loop_timer;
void dynamic_macro_record_start_user(void) {
is_dynamic_recording = true;
dynamic_loop_timer = timer_read();
ergodox_right_led_1_on();
}
void dynamic_macro_record_end_user(int8_t direction) {
is_dynamic_recording = false;
layer_state_set_user(layer_state);
}
#endif
void matrix_scan_kb(void) {
#ifdef ORYX_ENABLE
if(webusb_state.pairing == true) {
if(loops == 0) {
ergodox_right_led_1_off();
ergodox_right_led_2_off();
ergodox_right_led_3_off();
}
if(loops % WEBUSB_BLINK_STEPS == 0) {
if(is_on) {
ergodox_right_led_2_off();
} else {
ergodox_right_led_2_on();
}
is_on ^= 1;
}
if(loops > WEBUSB_BLINK_END) {
webusb_state.pairing = false;
layer_state_set_user(layer_state);
loops = 0;
}
loops++;
} else if(loops > 0) {
loops = 0;
layer_state_set_user(layer_state);
}
#endif
#ifdef DYNAMIC_MACRO_ENABLE
if (is_dynamic_recording) {
ergodox_right_led_1_off();
// if (timer_elapsed(dynamic_loop_timer) > 5)
{
static uint8_t counter;
counter++;
if (counter > 100) ergodox_right_led_1_on();
dynamic_loop_timer = timer_read();
}
}
#endif
#ifdef CAPS_LOCK_STATUS
led_t led_state = host_keyboard_led_state();
if(led_state.caps_lock) {
ergodox_right_led_3_on();
}
else {
uint8_t layer = get_highest_layer(layer_state);
if(layer != 3) {
ergodox_right_led_3_off();
}
}
#endif
matrix_scan_user();
}

286
betalupi_ergodox.h Normal file
View File

@ -0,0 +1,286 @@
/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
Copyright 2015 ZSA Technology Labs Inc (@zsa)
Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
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/>.
*/
#pragma once
#include "quantum.h"
#include <stdint.h>
#include <stdbool.h>
#include "i2c_master.h"
// I2C aliases and register addresses (see "mcp23018.md")
#define I2C_ADDR 0b0100000
#define I2C_ADDR_WRITE ( (I2C_ADDR<<1) | I2C_WRITE )
#define I2C_ADDR_READ ( (I2C_ADDR<<1) | I2C_READ )
#define IODIRA 0x00 // i/o direction register
#define IODIRB 0x01
#define GPPUA 0x0C // GPIO pull-up resistor register
#define GPPUB 0x0D
#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
#define GPIOB 0x13
#define OLATA 0x14 // output latch register
#define OLATB 0x15
extern i2c_status_t mcp23018_status;
#define ERGODOX_EZ_I2C_TIMEOUT 100
void init_ergodox(void);
void ergodox_blink_all_leds(void);
uint8_t init_mcp23018(void);
uint8_t ergodox_left_leds_update(void);
#ifndef LED_BRIGHTNESS_LO
#define LED_BRIGHTNESS_LO 15
#endif
#ifndef LED_BRIGHTNESS_HI
#define LED_BRIGHTNESS_HI 255
#endif
inline void ergodox_board_led_on(void) { DDRD |= (1<<6); PORTD |= (1<<6); }
inline void ergodox_right_led_1_on(void) { DDRB |= (1<<5); PORTB |= (1<<5); }
inline void ergodox_right_led_2_on(void) { DDRB |= (1<<6); PORTB |= (1<<6); }
inline void ergodox_right_led_3_on(void) { DDRB |= (1<<7); PORTB |= (1<<7); }
inline void ergodox_right_led_on(uint8_t led) { DDRB |= (1<<(led+4)); PORTB |= (1<<(led+4)); }
inline void ergodox_board_led_off(void) { DDRD &= ~(1<<6); PORTD &= ~(1<<6); }
inline void ergodox_right_led_1_off(void) { DDRB &= ~(1<<5); PORTB &= ~(1<<5); }
inline void ergodox_right_led_2_off(void) { DDRB &= ~(1<<6); PORTB &= ~(1<<6); }
inline void ergodox_right_led_3_off(void) { DDRB &= ~(1<<7); PORTB &= ~(1<<7); }
inline void ergodox_right_led_off(uint8_t led) { DDRB &= ~(1<<(led+4)); PORTB &= ~(1<<(led+4)); }
#ifdef LEFT_LEDS
bool ergodox_left_led_1;
bool ergodox_left_led_2;
bool ergodox_left_led_3;
inline void ergodox_left_led_1_on(void) { ergodox_left_led_1 = 1; }
inline void ergodox_left_led_2_on(void) { ergodox_left_led_2 = 1; }
inline void ergodox_left_led_3_on(void) { ergodox_left_led_3 = 1; }
inline void ergodox_left_led_1_off(void) { ergodox_left_led_1 = 0; }
inline void ergodox_left_led_2_off(void) { ergodox_left_led_2 = 0; }
inline void ergodox_left_led_3_off(void) { ergodox_left_led_3 = 0; }
#endif // LEFT_LEDS
inline void ergodox_led_all_on(void)
{
ergodox_board_led_on();
ergodox_right_led_1_on();
ergodox_right_led_2_on();
ergodox_right_led_3_on();
#ifdef LEFT_LEDS
ergodox_left_led_1_on();
ergodox_left_led_2_on();
ergodox_left_led_3_on();
#endif // LEFT_LEDS
}
inline void ergodox_led_all_off(void)
{
ergodox_board_led_off();
ergodox_right_led_1_off();
ergodox_right_led_2_off();
ergodox_right_led_3_off();
#ifdef LEFT_LEDS
ergodox_left_led_1_off();
ergodox_left_led_2_off();
ergodox_left_led_3_off();
#endif // LEFT_LEDS
}
inline void ergodox_right_led_1_set(uint8_t n) { OCR1A = n; }
inline void ergodox_right_led_2_set(uint8_t n) { OCR1B = n; }
inline void ergodox_right_led_3_set(uint8_t n) { OCR1C = n; }
inline void ergodox_right_led_set(uint8_t led, uint8_t n) {
(led == 1) ? (OCR1A = n) :
(led == 2) ? (OCR1B = n) :
(OCR1C = n);
}
inline void ergodox_led_all_set(uint8_t n)
{
ergodox_right_led_1_set(n);
ergodox_right_led_2_set(n);
ergodox_right_led_3_set(n);
}
enum ergodox_ez_keycodes {
LED_LEVEL = SAFE_RANGE,
TOGGLE_LAYER_COLOR,
EZ_SAFE_RANGE,
};
typedef union {
uint32_t raw;
struct {
uint8_t led_level :3;
bool disable_layer_led :1;
bool rgb_matrix_enable :1;
};
} keyboard_config_t;
extern keyboard_config_t keyboard_config;
/*
* LEFT HAND: LINES 115-122
* RIGHT HAND: LINES 124-131
*/
#define LAYOUT_ergodox( \
\
k00,k01,k02,k03,k04,k05,k06, \
k10,k11,k12,k13,k14,k15,k16, \
k20,k21,k22,k23,k24,k25, \
k30,k31,k32,k33,k34,k35,k36, \
k40,k41,k42,k43,k44, \
k55,k56, \
k54, \
k53,k52,k51, \
\
k07,k08,k09,k0A,k0B,k0C,k0D, \
k17,k18,k19,k1A,k1B,k1C,k1D, \
k28,k29,k2A,k2B,k2C,k2D, \
k37,k38,k39,k3A,k3B,k3C,k3D, \
k49,k4A,k4B,k4C,k4D, \
k57,k58, \
k59, \
k5C,k5B,k5A ) \
\
/* matrix positions */ \
{ \
{ k00, k10, k20, k30, k40, KC_NO }, \
{ k01, k11, k21, k31, k41, k51 }, \
{ k02, k12, k22, k32, k42, k52 }, \
{ k03, k13, k23, k33, k43, k53 }, \
{ k04, k14, k24, k34, k44, k54 }, \
{ k05, k15, k25, k35, KC_NO, k55 }, \
{ k06, k16, KC_NO, k36, KC_NO, k56 }, \
\
{ k07, k17, KC_NO, k37,KC_NO, k57 }, \
{ k08, k18, k28, k38,KC_NO, k58 }, \
{ k09, k19, k29, k39, k49, k59 }, \
{ k0A, k1A, k2A, k3A, k4A, k5A }, \
{ k0B, k1B, k2B, k3B, k4B, k5B }, \
{ k0C, k1C, k2C, k3C, k4C, k5C }, \
{ k0D, k1D, k2D, k3D, k4D, KC_NO } \
}
/*
* LEFT HAND: LINES 158-165
* RIGHT HAND: LINES 167-174
*/
#define LAYOUT_ergodox_80( \
\
k00,k01,k02,k03,k04,k05,k06, \
k10,k11,k12,k13,k14,k15,k16, \
k20,k21,k22,k23,k24,k25, \
k30,k31,k32,k33,k34,k35,k36, \
k40,k41,k42,k43,k44, \
k55,k56, \
k45,k46,k54, \
k53,k52,k51, \
\
k07,k08,k09,k0A,k0B,k0C,k0D, \
k17,k18,k19,k1A,k1B,k1C,k1D, \
k28,k29,k2A,k2B,k2C,k2D, \
k37,k38,k39,k3A,k3B,k3C,k3D, \
k49,k4A,k4B,k4C,k4D, \
k57,k58, \
k59,k47,k48, \
k5C,k5B,k5A ) \
\
/* matrix positions */ \
{ \
{ k00, k10, k20, k30, k40, KC_NO }, \
{ k01, k11, k21, k31, k41, k51 }, \
{ k02, k12, k22, k32, k42, k52 }, \
{ k03, k13, k23, k33, k43, k53 }, \
{ k04, k14, k24, k34, k44, k54 }, \
{ k05, k15, k25, k35, k45, k55 }, \
{ k06, k16, KC_NO, k36, k46, k56 }, \
\
{ k07, k17, KC_NO, k37, k47, k57 }, \
{ k08, k18, k28, k38, k48, k58 }, \
{ k09, k19, k29, k39, k49, k59 }, \
{ k0A, k1A, k2A, k3A, k4A, k5A }, \
{ k0B, k1B, k2B, k3B, k4B, k5B }, \
{ k0C, k1C, k2C, k3C, k4C, k5C }, \
{ k0D, k1D, k2D, k3D, k4D, KC_NO } \
}
/* ---------- LEFT HAND ----------- ---------- RIGHT HAND ---------- */
#define LAYOUT_ergodox_pretty( \
L00,L01,L02,L03,L04,L05,L06, R00,R01,R02,R03,R04,R05,R06, \
L10,L11,L12,L13,L14,L15,L16, R10,R11,R12,R13,R14,R15,R16, \
L20,L21,L22,L23,L24,L25, R21,R22,R23,R24,R25,R26, \
L30,L31,L32,L33,L34,L35,L36, R30,R31,R32,R33,R34,R35,R36, \
L40,L41,L42,L43,L44, R42,R43,R44,R45,R46, \
L55,L56, R50,R51, \
L54, R52, \
L53,L52,L51, R55,R54,R53 ) \
\
/* matrix positions */ \
{ \
{ L00, L10, L20, L30, L40, KC_NO }, \
{ L01, L11, L21, L31, L41, L51 }, \
{ L02, L12, L22, L32, L42, L52 }, \
{ L03, L13, L23, L33, L43, L53 }, \
{ L04, L14, L24, L34, L44, L54 }, \
{ L05, L15, L25, L35, KC_NO, L55 }, \
{ L06, L16, KC_NO, L36, KC_NO, L56 }, \
\
{ R00, R10, KC_NO, R30,KC_NO, R50 }, \
{ R01, R11, R21, R31,KC_NO, R51 }, \
{ R02, R12, R22, R32, R42, R52 }, \
{ R03, R13, R23, R33, R43, R53 }, \
{ R04, R14, R24, R34, R44, R54 }, \
{ R05, R15, R25, R35, R45, R55 }, \
{ R06, R16, R26, R36, R46, KC_NO } \
}
/* ---------- LEFT HAND ----------- ---------- RIGHT HAND ---------- */
#define LAYOUT_ergodox_pretty_80( \
L00,L01,L02,L03,L04,L05,L06, R00,R01,R02,R03,R04,R05,R06, \
L10,L11,L12,L13,L14,L15,L16, R10,R11,R12,R13,R14,R15,R16, \
L20,L21,L22,L23,L24,L25, R21,R22,R23,R24,R25,R26, \
L30,L31,L32,L33,L34,L35,L36, R30,R31,R32,R33,R34,R35,R36, \
L40,L41,L42,L43,L44, R42,R43,R44,R45,R46, \
L55,L56, R50,R51, \
L45,L46,L54, R52,R40,R41, \
L53,L52,L51, R55,R54,R53 ) \
\
/* matrix positions */ \
{ \
{ L00, L10, L20, L30, L40, KC_NO }, \
{ L01, L11, L21, L31, L41, L51 }, \
{ L02, L12, L22, L32, L42, L52 }, \
{ L03, L13, L23, L33, L43, L53 }, \
{ L04, L14, L24, L34, L44, L54 }, \
{ L05, L15, L25, L35, L45, L55 }, \
{ L06, L16, KC_NO, L36, L46, L56 }, \
\
{ R00, R10, KC_NO, R30, R40, R50 }, \
{ R01, R11, R21, R31, R41, R51 }, \
{ R02, R12, R22, R32, R42, R52 }, \
{ R03, R13, R23, R33, R43, R53 }, \
{ R04, R14, R24, R34, R44, R54 }, \
{ R05, R15, R25, R35, R45, R55 }, \
{ R06, R16, R26, R36, R46, KC_NO } \
}

171
config.h Normal file
View File

@ -0,0 +1,171 @@
/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
Copyright 2015 ZSA Technology Labs Inc (@zsa)
Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
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/>.
*/
#pragma once
#include "config_common.h"
/* USB Device descriptor parameter */
#define VENDOR_ID 0x3297
#define PRODUCT_ID 0x4974
#define DEVICE_VER 0x0001
#define MANUFACTURER ZSA Technology Labs Inc
#define PRODUCT ErgoDox EZ
#define WEBUSB_LANDING_PAGE_URL u8"configure.ergodox-ez.com"
/* key matrix size */
#define MATRIX_ROWS 14
#define MATRIX_ROWS_PER_SIDE (MATRIX_ROWS / 2)
#define MATRIX_COLS 6
#define COL_EXPANDED { true, true, true, true, true, true, true, false, false, false, false, false, false, false }
#define MATRIX_ONBOARD_ROW_PINS { 0, 0, 0, 0, 0, 0, 0, B0, B1, B2, B3, D2, D3, C6 }
#define MATRIX_ONBOARD_COL_PINS { F0, F1, F4, F5, F6, F7 }
#define DIODE_DIRECTION COL2ROW
#define EXPANDER_COL_REGISTER GPIOB
#define EXPANDER_ROW_REGISTER GPIOA
#define MATRIX_EXPANDER_COL_PINS { 5, 4, 3, 2, 1, 0 }
#define MATRIX_EXPANDER_ROW_PINS { 0, 1, 2, 3, 4, 5, 6 }
#define MOUSEKEY_INTERVAL 20
#define MOUSEKEY_DELAY 0
#define MOUSEKEY_TIME_TO_MAX 60
#define MOUSEKEY_MAX_SPEED 7
#define MOUSEKEY_WHEEL_DELAY 400
#define MOUSEKEY_WHEEL_INTERVAL MOUSEKEY_INTERVAL
#define MOUSEKEY_WHEEL_MAX_SPEED MOUSEKEY_MAX_SPEED
#define MOUSEKEY_WHEEL_TIME_TO_MAX MOUSEKEY_TIME_TO_MAX
#define TAPPING_TOGGLE 1
/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST
#define TAPPING_TERM 200
#define IGNORE_MOD_TAP_INTERRUPT // this makes it possible to do rolling combos (zx) with keys that convert to other keys on hold (z becomes ctrl when you hold it, and when this option isn't enabled, z rapidly followed by x actually sends Ctrl-x. That's bad.)
/* key combination for command */
#define IS_COMMAND() ( \
get_mods() == (MOD_BIT(KC_LCTL) | MOD_BIT(KC_RCTL)) || \
get_mods() == (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)) \
)
/* number of backlight levels */
#define BACKLIGHT_LEVELS 3
#ifndef LED_BRIGHTNESS_LO
#define LED_BRIGHTNESS_LO 15
#endif
#ifndef LED_BRIGHTNESS_HI
#define LED_BRIGHTNESS_HI 255
#endif
#define LED_BRIGHTNESS_DEFAULT (LED_BRIGHTNESS_HI)
/* ws2812 RGB LED */
#define RGB_DI_PIN D7
#define RGBLIGHT_ANIMATIONS
#define RGBLIGHT_HUE_STEP 12
#define RGBLIGHT_SAT_STEP 255
#define RGBLIGHT_VAL_STEP 12
// Pick one of the modes
// Defaults to 15 mirror, for legacy behavior
// #define ERGODOX_LED_15 // Addresses 15 LEDs, but same position on both halves
// #define ERGODOX_LED_15_MIRROR // Addresses 15 LEDs, but are mirrored
// #define ERGODOX_LED_30 // Addresses all 30 LED individually
/* fix space cadet rollover issue */
#define DISABLE_SPACE_CADET_ROLLOVER
#define RGBW
#define RGBLIGHT_SLEEP
/*
* The debounce filtering reports a key/switch change directly,
* without any extra delay. After that the debounce logic will filter
* all further changes, until the key/switch reports the same state for
* the given count of scans.
* So a perfect switch will get a short debounce period and
* a bad key will get a much longer debounce period.
* The result is an adaptive debouncing period for each switch.
*
* If you don't define it here, the matrix code will default to
* 5, which is now closer to 10ms, but still plenty according to
* manufacturer specs.
*/
#define DEBOUNCE 30
#define USB_MAX_POWER_CONSUMPTION 500
// RGB backlight
#define DRIVER_ADDR_1 0b1110100
#define DRIVER_ADDR_2 0b1110111
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 24
#define DRIVER_2_LED_TOTAL 24
#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
#define RGB_MATRIX_LED_PROCESS_LIMIT 5
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
#define RGB_DISABLE_WHEN_USB_SUSPENDED true
// #define RGBLIGHT_COLOR_LAYER_0 0x00, 0x00, 0xFF
/* #define RGBLIGHT_COLOR_LAYER_1 0x00, 0x00, 0xFF */
/* #define RGBLIGHT_COLOR_LAYER_2 0xFF, 0x00, 0x00 */
/* #define RGBLIGHT_COLOR_LAYER_3 0x00, 0xFF, 0x00 */
/* #define RGBLIGHT_COLOR_LAYER_4 0xFF, 0xFF, 0x00 */
/* #define RGBLIGHT_COLOR_LAYER_5 0x00, 0xFF, 0xFF */
/* #define RGBLIGHT_COLOR_LAYER_6 0xFF, 0x00, 0xFF */
/* #define RGBLIGHT_COLOR_LAYER_7 0xFF, 0xFF, 0xFF */
/*
* Feature disable options
* These options are also useful to firmware size reduction.
*/
/* disable debug print */
// #define NO_DEBUG
/* disable print */
// #define NO_PRINT
/* disable action features */
//#define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT
#define NO_ACTION_MACRO
#define NO_ACTION_FUNCTION
//#define DEBUG_MATRIX_SCAN_RATE
/*
FROM ergodox_ez/glow/config.h
*/
#pragma once
#undef PRODUCT_ID
#define PRODUCT_ID 0x4976
#undef PRODUCT
#define PRODUCT ErgoDox

104
info.json Normal file
View File

@ -0,0 +1,104 @@
{
"keyboard_name": "ErgoDox EZ",
"url": "ergodox-ez.com",
"maintainer": "erez",
"width": 17,
"height": 8,
"layouts": {
"LAYOUT_ergodox": {
"layout": [
{"x":0, "y":0.375, "w":1.5}, {"x":1.5, "y":0.375}, {"x":2.5, "y":0.125}, {"x":3.5, "y":0}, {"x":4.5, "y":0.125}, {"x":5.5, "y":0.25}, {"x":6.5, "y":0.25},
{"x":0, "y":1.375, "w":1.5}, {"x":1.5, "y":1.375}, {"x":2.5, "y":1.125}, {"x":3.5, "y":1}, {"x":4.5, "y":1.125}, {"x":5.5, "y":1.25}, {"x":6.5, "y":1.25, "h":1.5},
{"x":0, "y":2.375, "w":1.5}, {"x":1.5, "y":2.375}, {"x":2.5, "y":2.125}, {"x":3.5, "y":2}, {"x":4.5, "y":2.125}, {"x":5.5, "y":2.25},
{"x":0, "y":3.375, "w":1.5}, {"x":1.5, "y":3.375}, {"x":2.5, "y":3.125}, {"x":3.5, "y":3}, {"x":4.5, "y":3.125}, {"x":5.5, "y":3.25}, {"x":6.5, "y":2.75, "h":1.5},
{"x":0.5, "y":4.375}, {"x":1.5, "y":4.375}, {"x":2.5, "y":4.125}, {"x":3.5, "y":4}, {"x":4.5, "y":4.125},
{"x":6, "y":5}, {"x":7, "y":5},
{"x":7, "y":6},
{"x":5, "y":6, "h":2}, {"x":6, "y":6, "h":2}, {"x":7, "y":7},
{"x":9.5, "y":0.25}, {"x":10.5, "y":0.25}, {"x":11.5, "y":0.125}, {"x":12.5, "y":0}, {"x":13.5, "y":0.125}, {"x":14.5, "y":0.375}, {"x":15.5, "y":0.375, "w":1.5},
{"x":9.5, "y":1.25, "h":1.5}, {"x":10.5, "y":1.25}, {"x":11.5, "y":1.125}, {"x":12.5, "y":1}, {"x":13.5, "y":1.125}, {"x":14.5, "y":1.375}, {"x":15.5, "y":1.375, "w":1.5},
{"x":10.5, "y":2.25}, {"x":11.5, "y":2.125}, {"x":12.5, "y":2}, {"x":13.5, "y":2.125}, {"x":14.5, "y":2.375}, {"x":15.5, "y":2.375, "w":1.5},
{"x":9.5, "y":2.75, "h":1.5}, {"x":10.5, "y":3.25}, {"x":11.5, "y":3.125}, {"x":12.5, "y":3}, {"x":13.5, "y":3.125}, {"x":14.5, "y":3.375}, {"x":15.5, "y":3.375, "w":1.5},
{"x":11.5, "y":4.125}, {"x":12.5, "y":4}, {"x":13.5, "y":4.125}, {"x":14.5, "y":4.375}, {"x":15.5, "y":4.375},
{"x":9, "y":5}, {"x":10, "y":5},
{"x":9, "y":6},
{"x":9, "y":7}, {"x":10, "y":6, "h":2}, {"x":11, "y":6, "h":2}
]
},
"LAYOUT_ergodox_pretty": {
"layout": [
{"x":0, "y":0.375, "w":1.5}, {"x":1.5, "y":0.375}, {"x":2.5, "y":0.125}, {"x":3.5, "y":0}, {"x":4.5, "y":0.125}, {"x":5.5, "y":0.25}, {"x":6.5, "y":0.25},
{"x":9.5, "y":0.25}, {"x":10.5, "y":0.25}, {"x":11.5, "y":0.125}, {"x":12.5, "y":0}, {"x":13.5, "y":0.125}, {"x":14.5, "y":0.375}, {"x":15.5, "y":0.375, "w":1.5},
{"x":0, "y":1.375, "w":1.5}, {"x":1.5, "y":1.375}, {"x":2.5, "y":1.125}, {"x":3.5, "y":1}, {"x":4.5, "y":1.125}, {"x":5.5, "y":1.25}, {"x":6.5, "y":1.25, "h":1.5},
{"x":9.5, "y":1.25, "h":1.5}, {"x":10.5, "y":1.25}, {"x":11.5, "y":1.125}, {"x":12.5, "y":1}, {"x":13.5, "y":1.125}, {"x":14.5, "y":1.375}, {"x":15.5, "y":1.375, "w":1.5},
{"x":0, "y":2.375, "w":1.5}, {"x":1.5, "y":2.375}, {"x":2.5, "y":2.125}, {"x":3.5, "y":2}, {"x":4.5, "y":2.125}, {"x":5.5, "y":2.25},
{"x":10.5, "y":2.25}, {"x":11.5, "y":2.125}, {"x":12.5, "y":2}, {"x":13.5, "y":2.125}, {"x":14.5, "y":2.375}, {"x":15.5, "y":2.375, "w":1.5},
{"x":0, "y":3.375, "w":1.5}, {"x":1.5, "y":3.375}, {"x":2.5, "y":3.125}, {"x":3.5, "y":3}, {"x":4.5, "y":3.125}, {"x":5.5, "y":3.25}, {"x":6.5, "y":2.75, "h":1.5},
{"x":9.5, "y":2.75, "h":1.5}, {"x":10.5, "y":3.25}, {"x":11.5, "y":3.125}, {"x":12.5, "y":3}, {"x":13.5, "y":3.125}, {"x":14.5, "y":3.375}, {"x":15.5, "y":3.375, "w":1.5},
{"x":0.5, "y":4.375}, {"x":1.5, "y":4.375}, {"x":2.5, "y":4.125}, {"x":3.5, "y":4}, {"x":4.5, "y":4.125},
{"x":11.5, "y":4.125}, {"x":12.5, "y":4}, {"x":13.5, "y":4.125}, {"x":14.5, "y":4.375}, {"x":15.5, "y":4.375},
{"x":6, "y":5}, {"x":7, "y":5}, {"x":9, "y":5}, {"x":10, "y":5},
{"x":7, "y":6}, {"x":9, "y":6},
{"x":5, "y":6, "h":2}, {"x":6, "y":6, "h":2}, {"x":7, "y":7}, {"x":9, "y":7}, {"x":10, "y":6, "h":2}, {"x":11, "y":6, "h":2}
]
},
"LAYOUT_ergodox_80": {
"layout": [
{"x":0, "y":0.375, "w":1.5}, {"x":1.5, "y":0.375}, {"x":2.5, "y":0.125}, {"x":3.5, "y":0}, {"x":4.5, "y":0.125}, {"x":5.5, "y":0.25}, {"x":6.5, "y":0.25},
{"x":0, "y":1.375, "w":1.5}, {"x":1.5, "y":1.375}, {"x":2.5, "y":1.125}, {"x":3.5, "y":1}, {"x":4.5, "y":1.125}, {"x":5.5, "y":1.25}, {"x":6.5, "y":1.25, "h":1.5},
{"x":0, "y":2.375, "w":1.5}, {"x":1.5, "y":2.375}, {"x":2.5, "y":2.125}, {"x":3.5, "y":2}, {"x":4.5, "y":2.125}, {"x":5.5, "y":2.25},
{"x":0, "y":3.375, "w":1.5}, {"x":1.5, "y":3.375}, {"x":2.5, "y":3.125}, {"x":3.5, "y":3}, {"x":4.5, "y":3.125}, {"x":5.5, "y":3.25}, {"x":6.5, "y":2.75, "h":1.5},
{"x":0.5, "y":4.375}, {"x":1.5, "y":4.375}, {"x":2.5, "y":4.125}, {"x":3.5, "y":4}, {"x":4.5, "y":4.125},
{"x":6, "y":5}, {"x":7, "y":5},
{"x":5, "y":6}, {"x":6, "y":6}, {"x":7, "y":6},
{"x":5, "y":7}, {"x":6, "y":7}, {"x":7, "y":7},
{"x":9.5, "y":0.25}, {"x":10.5, "y":0.25}, {"x":11.5, "y":0.125}, {"x":12.5, "y":0}, {"x":13.5, "y":0.125}, {"x":14.5, "y":0.375}, {"x":15.5, "y":0.375, "w":1.5},
{"x":9.5, "y":1.25, "h":1.5}, {"x":10.5, "y":1.25}, {"x":11.5, "y":1.125}, {"x":12.5, "y":1}, {"x":13.5, "y":1.125}, {"x":14.5, "y":1.375}, {"x":15.5, "y":1.375, "w":1.5},
{"x":10.5, "y":2.25}, {"x":11.5, "y":2.125}, {"x":12.5, "y":2}, {"x":13.5, "y":2.125}, {"x":14.5, "y":2.375}, {"x":15.5, "y":2.375, "w":1.5},
{"x":9.5, "y":2.75, "h":1.5}, {"x":10.5, "y":3.25}, {"x":11.5, "y":3.125}, {"x":12.5, "y":3}, {"x":13.5, "y":3.125}, {"x":14.5, "y":3.375}, {"x":15.5, "y":3.375, "w":1.5},
{"x":11.5, "y":4.125}, {"x":12.5, "y":4}, {"x":13.5, "y":4.125}, {"x":14.5, "y":4.375}, {"x":15.5, "y":4.375},
{"x":9, "y":5}, {"x":10, "y":5},
{"x":9, "y":6}, {"x":10, "y":6}, {"x":11, "y":6},
{"x":9, "y":7}, {"x":10, "y":7}, {"x":11, "y":7}
]
},
"LAYOUT_ergodox_pretty_80": {
"layout": [
{"x":0, "y":0.375, "w":1.5}, {"x":1.5, "y":0.375}, {"x":2.5, "y":0.125}, {"x":3.5, "y":0}, {"x":4.5, "y":0.125}, {"x":5.5, "y":0.25}, {"x":6.5, "y":0.25},
{"x":9.5, "y":0.25}, {"x":10.5, "y":0.25}, {"x":11.5, "y":0.125}, {"x":12.5, "y":0}, {"x":13.5, "y":0.125}, {"x":14.5, "y":0.375}, {"x":15.5, "y":0.375, "w":1.5},
{"x":0, "y":1.375, "w":1.5}, {"x":1.5, "y":1.375}, {"x":2.5, "y":1.125}, {"x":3.5, "y":1}, {"x":4.5, "y":1.125}, {"x":5.5, "y":1.25}, {"x":6.5, "y":1.25, "h":1.5},
{"x":9.5, "y":1.25, "h":1.5}, {"x":10.5, "y":1.25}, {"x":11.5, "y":1.125}, {"x":12.5, "y":1}, {"x":13.5, "y":1.125}, {"x":14.5, "y":1.375}, {"x":15.5, "y":1.375, "w":1.5},
{"x":0, "y":2.375, "w":1.5}, {"x":1.5, "y":2.375}, {"x":2.5, "y":2.125}, {"x":3.5, "y":2}, {"x":4.5, "y":2.125}, {"x":5.5, "y":2.25},
{"x":10.5, "y":2.25}, {"x":11.5, "y":2.125}, {"x":12.5, "y":2}, {"x":13.5, "y":2.125}, {"x":14.5, "y":2.375}, {"x":15.5, "y":2.375, "w":1.5},
{"x":0, "y":3.375, "w":1.5}, {"x":1.5, "y":3.375}, {"x":2.5, "y":3.125}, {"x":3.5, "y":3}, {"x":4.5, "y":3.125}, {"x":5.5, "y":3.25}, {"x":6.5, "y":2.75, "h":1.5},
{"x":9.5, "y":2.75, "h":1.5}, {"x":10.5, "y":3.25}, {"x":11.5, "y":3.125}, {"x":12.5, "y":3}, {"x":13.5, "y":3.125}, {"x":14.5, "y":3.375}, {"x":15.5, "y":3.375, "w":1.5},
{"x":0.5, "y":4.375}, {"x":1.5, "y":4.375}, {"x":2.5, "y":4.125}, {"x":3.5, "y":4}, {"x":4.5, "y":4.125},
{"x":11.5, "y":4.125}, {"x":12.5, "y":4}, {"x":13.5, "y":4.125}, {"x":14.5, "y":4.375}, {"x":15.5, "y":4.375},
{"x":6, "y":5}, {"x":7, "y":5}, {"x":9, "y":5}, {"x":10, "y":5},
{"x":5, "y":6}, {"x":6, "y":6}, {"x":7, "y":6}, {"x":9, "y":6}, {"x":10, "y":6}, {"x":11, "y":6},
{"x":5, "y":7}, {"x":6, "y":7}, {"x":7, "y":7}, {"x":9, "y":7}, {"x":10, "y":7}, {"x":11, "y":7}
]
}
}
}

17
keymaps/default/config.h Normal file
View File

@ -0,0 +1,17 @@
/*
Set any config.h overrides for your specific keymap here.
See config.h options at https://docs.qmk.fm/#/config_options?id=the-configh-file
*/
#define ORYX_CONFIGURATOR
#undef RGB_MATRIX_HUE_STEP
#define RGB_MATRIX_HUE_STEP 10
#define USB_SUSPEND_WAKEUP_DELAY 0
#undef MOUSEKEY_MAX_SPEED
#define MOUSEKEY_MAX_SPEED 5
#undef MOUSEKEY_TIME_TO_MAX
#define MOUSEKEY_TIME_TO_MAX 100
#define CAPS_LOCK_STATUS
#define RGB_MATRIX_STARTUP_SPD 60

428
keymaps/default/keymap.c Normal file
View File

@ -0,0 +1,428 @@
#include "betalupi_ergodox.h"
#include "version.h"
//#include "keymap_german.h"
//#include "keymap_nordic.h"
//#include "keymap_french.h"
//#include "keymap_spanish.h"
//#include "keymap_hungarian.h"
//#include "keymap_swedish.h"
//#include "keymap_br_abnt2.h"
//#include "keymap_canadian_multilingual.h"
//#include "keymap_german_ch.h"
//#include "keymap_jp.h"
//#include "keymap_korean.h"
//#include "keymap_bepo.h"
//#include "keymap_italian.h"
//#include "keymap_slovenian.h"
//#include "keymap_lithuanian_azerty.h"
//#include "keymap_danish.h"
//#include "keymap_norwegian.h"
//#include "keymap_portuguese.h"
//#include "keymap_contributions.h"
//#include "keymap_czech.h"
//#include "keymap_romanian.h"
#include "keymap_russian.h"
//#include "keymap_uk.h"
//#include "keymap_estonian.h"
//#include "keymap_belgian.h"
#include "keymap_us_international.h"
#define KC_MAC_UNDO LGUI(KC_Z)
#define KC_MAC_CUT LGUI(KC_X)
#define KC_MAC_COPY LGUI(KC_C)
#define KC_MAC_PASTE LGUI(KC_V)
#define KC_PC_UNDO LCTL(KC_Z)
#define KC_PC_CUT LCTL(KC_X)
#define KC_PC_COPY LCTL(KC_C)
#define KC_PC_PASTE LCTL(KC_V)
#define ES_LESS_MAC KC_GRAVE
#define ES_GRTR_MAC LSFT(KC_GRAVE)
#define ES_BSLS_MAC ALGR(KC_6)
#define NO_PIPE_ALT KC_GRAVE
#define NO_BSLS_ALT KC_EQUAL
#define LSA_T(kc) MT(MOD_LSFT | MOD_LALT, kc)
#define BP_NDSH_MAC ALGR(KC_8)
enum custom_keycodes {
RGB_SLD = EZ_SAFE_RANGE,
HSV_136_138_245,
HSV_24_210_255,
HSV_0_0_255,
ST_MACRO_0,
ST_MACRO_1,
RU_LAYER,
EN_LAYER,
RU_SYMBOL,
};
enum tap_dance_codes {
DANCE_0,
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT_ergodox_pretty(
KC_ESCAPE, KC_1, KC_2, KC_3, KC_4, KC_5, TG(2), LCTL(KC_LALT), KC_6, KC_7, KC_8, KC_9, KC_0, LGUI(KC_TAB),
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_LGUI, KC_TRANSPARENT, KC_Y, KC_U, KC_I, KC_O, KC_TRANSPARENT, TG(6),
KC_DELETE, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, MO(3), KC_L, KC_TRANSPARENT,
KC_LCTRL, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_TRANSPARENT, KC_TRANSPARENT, KC_N, KC_M, KC_P, KC_DOT, KC_COMMA, KC_TRANSPARENT,
OSL(7), OSL(5), KC_LALT, KC_LSHIFT, MO(4), KC_RIGHT, KC_TRANSPARENT, KC_TRANSPARENT, OSL(5), KC_TRANSPARENT,
KC_PSCREEN, LT(8,KC_NO), LGUI(KC_SPACE), RU_LAYER,
TD(DANCE_0), TG(1),
KC_SPACE, KC_BSPACE, LCTL(KC_BSPACE), KC_DELETE, KC_RSHIFT, KC_ENTER
),
[1] = LAYOUT_ergodox_pretty(
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_Q, KC_W, KC_F, KC_P, KC_B, KC_TRANSPARENT, KC_TRANSPARENT, KC_J, KC_L, KC_U, KC_O, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_A, KC_R, KC_S, KC_T, KC_G, KC_M, KC_N, KC_E, KC_TRANSPARENT, KC_I, KC_TRANSPARENT,
KC_TRANSPARENT, KC_Z, KC_X, KC_C, KC_D, KC_V, KC_TRANSPARENT, KC_TRANSPARENT, KC_K, KC_H, KC_O, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT
),
[2] = LAYOUT_ergodox_pretty(
KC_TRANSPARENT, KC_CIRC, KC_NO, KC_HASH, KC_DLR, KC_PERC, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_NO, KC_7, KC_8, KC_9, KC_ASTR, KC_SLASH, KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT,
KC_TRANSPARENT, KC_PLUS, KC_4, KC_5, KC_6, KC_0, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT,
KC_TRANSPARENT, KC_MINUS, KC_1, KC_2, KC_3, KC_DOT, KC_TRANSPARENT, KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_NO, KC_NO, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT
),
[3] = LAYOUT_ergodox_pretty(
KC_NO, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_NO, KC_NO, KC_CIRC, KC_AMPR, KC_ASTR, KC_NO, KC_NO, KC_NO,
KC_NO, KC_GRAVE, KC_LPRN, KC_RPRN, KC_QUES, KC_LCBR, KC_NO, KC_NO, KC_LABK, KC_RABK, KC_SLASH, KC_NO, KC_BSLASH, KC_NO,
KC_NO, KC_TILD, KC_QUOTE, KC_COMMA, KC_DOT, KC_DQUO, KC_UNDS, KC_MINUS, KC_COLN, KC_TRANSPARENT, KC_PIPE, KC_NO,
KC_NO, KC_NO, KC_LBRACKET, KC_RBRACKET, KC_EXLM, KC_RCBR, KC_NO, KC_NO, KC_EQUAL, KC_PLUS, KC_SCOLON, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO,
KC_TRANSPARENT, KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT
),
[4] = LAYOUT_ergodox_pretty(
KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_TRANSPARENT, KC_LEFT, KC_RIGHT, KC_UP, KC_NO, KC_NO, KC_TRANSPARENT, KC_TRANSPARENT, KC_NO, KC_PGUP, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT,
KC_TRANSPARENT, LALT(KC_LCTRL), KC_LEFT, KC_DOWN, KC_RIGHT, KC_NO, KC_NO, KC_PGDOWN, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT,
KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT, KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT
),
[5] = LAYOUT_ergodox_pretty(
KC_TRANSPARENT, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRANSPARENT, KC_TRANSPARENT, KC_F6, KC_F7, KC_F9, KC_F9, KC_F10, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT
),
[6] = LAYOUT_ergodox_pretty(
KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_TRANSPARENT, KC_NO, KC_MS_WH_UP, KC_MS_UP, KC_MS_WH_DOWN, KC_NO, KC_NO, TO(0), KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT,
KC_TRANSPARENT, KC_NO, KC_MS_LEFT, KC_MS_DOWN, KC_MS_RIGHT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
TO(7), KC_NO, KC_NO, KC_TRANSPARENT, KC_MS_BTN3, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_TRANSPARENT, KC_NO, KC_NO, KC_TRANSPARENT,
KC_NO, KC_TRANSPARENT,
KC_MS_BTN1, KC_MS_BTN2, KC_NO, KC_NO, KC_LGUI, KC_TRANSPARENT
),
[7] = LAYOUT_ergodox_pretty(
KC_TRANSPARENT, LCTL(LGUI(LSFT(KC_1))),LCTL(LGUI(LSFT(KC_2))),LCTL(LGUI(LSFT(KC_3))),LCTL(LGUI(LSFT(KC_4))),KC_NO, ST_MACRO_0, ST_MACRO_1, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_TRANSPARENT, LALT(LCTL(KC_UP)),KC_NO, LCTL(LGUI(KC_SPACE)),LGUI(KC_T), KC_NO, KC_NO, KC_NO, KC_NO, LCTL(LGUI(KC_UP)),KC_NO, LGUI(KC_P), KC_NO,
KC_NO, LALT(LCTL(KC_LEFT)),LALT(LCTL(KC_DOWN)),LALT(LCTL(KC_RIGHT)),LGUI(KC_F), LGUI(KC_M), KC_NO, LCTL(LGUI(KC_LEFT)),LCTL(LGUI(KC_DOWN)),LCTL(LGUI(KC_RIGHT)),KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, LGUI(LSFT(KC_C)),LGUI(KC_N), KC_NO, KC_NO, KC_NO, KC_NO, LGUI(KC_H), LGUI(KC_J), KC_NO, KC_NO, KC_NO,
TO(0), KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_MEDIA_PREV_TRACK,KC_MEDIA_NEXT_TRACK,
KC_NO, KC_AUDIO_VOL_UP,
LGUI(KC_ENTER), LGUI(KC_BSLASH),KC_NO, KC_AUDIO_VOL_DOWN,KC_MEDIA_STOP, KC_MEDIA_PLAY_PAUSE
),
[8] = LAYOUT_ergodox_pretty(
KC_TRANSPARENT, HSV_136_138_245,HSV_24_210_255, HSV_0_0_255, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, LED_LEVEL, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, RESET,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, RGB_HUI, RGB_SAI, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, RGB_HUD, RGB_SAD, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
RGB_TOG, KC_TRANSPARENT, KC_NO, RGB_TOG,
RGB_SPI, KC_NO,
RGB_MOD, RGB_SLD, RGB_SPD, TOGGLE_LAYER_COLOR,RGB_VAD, RGB_VAI
),
[9] = LAYOUT_ergodox_pretty(
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, RU_NUM, RU_RUBL, KC_TRANSPARENT,
KC_TRANSPARENT, RU_CHE, RU_SHA, RU_IE, RU_ER, RU_TE, RU_YO, RU_SOFT, RU_U, RU_YU, RU_I, RU_O, RU_SHCH, KC_TRANSPARENT,
KC_TRANSPARENT, RU_A, RU_ES, RU_DE, RU_EF, RU_GHE, RU_HA, RU_ZHE, RU_KA, RU_SYMBOL, RU_EL, KC_TRANSPARENT,
KC_TRANSPARENT, RU_ZE, RU_YA, RU_TSE, RU_VE, RU_BE, RU_E, RU_HARD, RU_EN, RU_EM, RU_PE, RU_YERU, RU_SHTI, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, EN_LAYER,
KC_TRANSPARENT, KC_TRANSPARENT,
KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT
),
[10] = LAYOUT_ergodox_pretty(
KC_NO, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_NO, KC_NO, KC_CIRC, KC_AMPR, KC_ASTR, KC_NO, KC_NO, KC_NO,
KC_NO, KC_GRAVE, KC_LPRN, KC_RPRN, KC_QUES, KC_LCBR, KC_NO, KC_NO, KC_LABK, KC_RABK, KC_SLASH, KC_NO, KC_BSLASH, KC_NO,
KC_NO, KC_TILD, KC_QUOTE, KC_COMMA, KC_DOT, KC_DQUO, KC_UNDS, KC_MINUS, KC_COLN, RU_SYMBOL, KC_PIPE, KC_NO,
KC_NO, KC_NO, KC_LBRACKET, KC_RBRACKET, KC_EXLM, KC_RCBR, KC_NO, KC_NO, KC_EQUAL, KC_PLUS, KC_SCOLON, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO,
KC_TRANSPARENT, KC_TRANSPARENT, KC_NO, KC_NO, KC_NO, KC_TRANSPARENT
),
};
extern bool g_suspend_state;
extern rgb_config_t rgb_matrix_config;
void keyboard_post_init_user(void) {
rgb_matrix_enable();
}
const uint8_t PROGMEM ledmap[][DRIVER_LED_TOTAL][3] = {
[1] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {243,222,234}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {243,222,234}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} },
[2] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {32,176,255}, {85,203,158}, {85,203,158}, {85,203,158}, {0,0,0}, {85,203,158}, {85,203,158}, {85,203,158}, {85,203,158}, {32,176,255}, {32,176,255}, {85,203,158}, {85,203,158}, {85,203,158}, {32,176,255}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} },
[3] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {85,203,158}, {85,203,158}, {134,255,213}, {0,0,0}, {134,255,213}, {134,255,213}, {85,203,158}, {243,222,234}, {10,225,255}, {134,255,213}, {85,203,158}, {85,203,158}, {243,222,234}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {134,255,213}, {243,222,234}, {134,255,213}, {134,255,213}, {10,225,255}, {243,222,234}, {243,222,234}, {243,222,234}, {243,222,234}, {10,225,255}, {134,255,213}, {243,222,234}, {134,255,213}, {134,255,213}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} },
[4] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {85,203,158}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {85,203,158}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {85,203,158}, {32,176,255}, {32,176,255}, {0,0,0}, {85,203,158}, {85,203,158}, {85,203,158}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {243,222,234}, {0,0,0}, {0,0,0}, {0,0,0} },
[5] = { {134,255,213}, {134,255,213}, {134,255,213}, {134,255,213}, {134,255,213}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {134,255,213}, {134,255,213}, {134,255,213}, {134,255,213}, {134,255,213}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} },
[6] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {243,222,234}, {0,0,0}, {0,0,0}, {0,0,0}, {243,222,234}, {243,222,234}, {243,222,234}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {243,222,234}, {0,0,0}, {0,0,0}, {0,0,0} },
[7] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {85,203,158}, {0,0,0}, {14,255,255}, {0,0,0}, {85,203,158}, {85,203,158}, {85,203,158}, {0,0,0}, {0,0,0}, {134,255,213}, {134,255,213}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {134,255,213}, {134,255,213}, {0,0,0}, {85,203,158}, {0,0,0}, {134,255,213}, {134,255,213}, {85,203,158}, {85,203,158}, {85,203,158}, {0,0,0}, {134,255,213}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} },
[9] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,165}, {0,0,165}, {0,0,165}, {0,0,165}, {0,0,165}, {153,255,153}, {153,255,153}, {153,255,153}, {153,255,153}, {153,255,153}, {0,255,145}, {0,255,145}, {0,255,145}, {0,255,145}, {0,255,145}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,165}, {0,0,165}, {0,0,165}, {0,0,165}, {0,0,165}, {153,255,153}, {153,255,153}, {153,255,153}, {153,255,153}, {153,255,153}, {0,255,145}, {0,255,145}, {0,255,145}, {0,255,145}, {0,255,145}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} },
[10] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {85,203,158}, {85,203,158}, {134,255,213}, {0,0,0}, {134,255,213}, {134,255,213}, {85,203,158}, {243,222,234}, {10,225,255}, {134,255,213}, {85,203,158}, {85,203,158}, {243,222,234}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {134,255,213}, {243,222,234}, {134,255,213}, {134,255,213}, {10,225,255}, {243,222,234}, {243,222,234}, {243,222,234}, {243,222,234}, {10,225,255}, {134,255,213}, {243,222,234}, {134,255,213}, {134,255,213}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} },
};
void set_layer_color(int layer) {
for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
HSV hsv = {
.h = pgm_read_byte(&ledmap[layer][i][0]),
.s = pgm_read_byte(&ledmap[layer][i][1]),
.v = pgm_read_byte(&ledmap[layer][i][2]),
};
if (!hsv.h && !hsv.s && !hsv.v) {
rgb_matrix_set_color( i, 0, 0, 0 );
} else {
RGB rgb = hsv_to_rgb( hsv );
float f = (float)rgb_matrix_config.hsv.v / UINT8_MAX;
rgb_matrix_set_color( i, f * rgb.r, f * rgb.g, f * rgb.b );
}
}
}
void rgb_matrix_indicators_user(void) {
if (g_suspend_state || keyboard_config.disable_layer_led) { return; }
switch (biton32(layer_state)) {
case 1:
set_layer_color(1);
break;
case 2:
set_layer_color(2);
break;
case 3:
set_layer_color(3);
break;
case 4:
set_layer_color(4);
break;
case 5:
set_layer_color(5);
break;
case 6:
set_layer_color(6);
break;
case 7:
set_layer_color(7);
break;
case 9:
set_layer_color(9);
break;
case 10:
set_layer_color(10);
break;
default:
if (rgb_matrix_get_flags() == LED_FLAG_NONE)
rgb_matrix_set_color_all(0, 0, 0);
break;
}
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case ST_MACRO_0:
if (record->event.pressed) {
SEND_STRING(SS_LCTL(SS_LGUI(SS_LSFT(SS_TAP(X_R)))));
}
break;
case ST_MACRO_1:
if (record->event.pressed) {
SEND_STRING(SS_LGUI(SS_TAP(X_P)) SS_DELAY(100) SS_TAP(X_Y) SS_DELAY(100) SS_TAP(X_ENTER));
}
break;
case RU_LAYER:
if (record->event.pressed) {
SEND_STRING(SS_LGUI(SS_LSFT(SS_LCTL(SS_TAP(X_9)))));
layer_move(9);
}
break;
case EN_LAYER:
if (record->event.pressed) {
SEND_STRING(SS_LGUI(SS_LSFT(SS_LCTL(SS_TAP(X_0)))));
layer_move(0);
}
break;
case RU_SYMBOL:
if (record->event.pressed) {
SEND_STRING(SS_LGUI(SS_LSFT(SS_LCTL(SS_TAP(X_0)))));
layer_move(10);
} else {
SEND_STRING(SS_LGUI(SS_LSFT(SS_LCTL(SS_TAP(X_9)))));
layer_move(9);
}
break;
case RGB_SLD:
if (record->event.pressed) {
rgblight_mode(1);
}
return false;
case HSV_136_138_245:
if (record->event.pressed) {
rgblight_mode(1);
rgblight_sethsv(136,138,245);
}
return false;
case HSV_24_210_255:
if (record->event.pressed) {
rgblight_mode(1);
rgblight_sethsv(24,210,255);
}
return false;
case HSV_0_0_255:
if (record->event.pressed) {
rgblight_mode(1);
rgblight_sethsv(0,0,255);
}
return false;
}
return true;
}
uint32_t layer_state_set_user(uint32_t state) {
uint8_t layer = biton32(state);
ergodox_board_led_off();
ergodox_right_led_1_off();
ergodox_right_led_2_off();
ergodox_right_led_3_off();
switch (layer) {
case 1:
ergodox_right_led_1_on();
break;
case 2:
ergodox_right_led_2_on();
break;
case 3:
ergodox_right_led_3_on();
break;
case 4:
ergodox_right_led_1_on();
ergodox_right_led_2_on();
break;
case 5:
ergodox_right_led_1_on();
ergodox_right_led_3_on();
break;
case 6:
ergodox_right_led_2_on();
ergodox_right_led_3_on();
break;
case 7:
ergodox_right_led_1_on();
ergodox_right_led_2_on();
ergodox_right_led_3_on();
break;
default:
break;
}
return state;
};
typedef struct {
bool is_press_action;
uint8_t step;
} tap;
enum {
SINGLE_TAP = 1,
SINGLE_HOLD,
DOUBLE_TAP,
DOUBLE_HOLD,
DOUBLE_SINGLE_TAP,
MORE_TAPS
};
static tap dance_state[1];
uint8_t dance_step(qk_tap_dance_state_t *state);
uint8_t dance_step(qk_tap_dance_state_t *state) {
if (state->count == 1) {
if (state->interrupted || !state->pressed) return SINGLE_TAP;
else return SINGLE_HOLD;
} else if (state->count == 2) {
if (state->interrupted) return DOUBLE_SINGLE_TAP;
else if (state->pressed) return DOUBLE_HOLD;
else return DOUBLE_TAP;
}
return MORE_TAPS;
}
void on_dance_0(qk_tap_dance_state_t *state, void *user_data);
void dance_0_finished(qk_tap_dance_state_t *state, void *user_data);
void dance_0_reset(qk_tap_dance_state_t *state, void *user_data);
void on_dance_0(qk_tap_dance_state_t *state, void *user_data) {
if(state->count == 3) {
tap_code16(LGUI(KC_L));
tap_code16(LGUI(KC_L));
tap_code16(LGUI(KC_L));
}
if(state->count > 3) {
tap_code16(LGUI(KC_L));
}
}
void dance_0_finished(qk_tap_dance_state_t *state, void *user_data) {
dance_state[0].step = dance_step(state);
switch (dance_state[0].step) {
case SINGLE_TAP: register_code16(LGUI(KC_L)); break;
case DOUBLE_TAP: register_code16(LGUI(KC_K)); break;
case DOUBLE_SINGLE_TAP: tap_code16(LGUI(KC_L)); register_code16(LGUI(KC_L));
}
}
void dance_0_reset(qk_tap_dance_state_t *state, void *user_data) {
wait_ms(10);
switch (dance_state[0].step) {
case SINGLE_TAP: unregister_code16(LGUI(KC_L)); break;
case DOUBLE_TAP: unregister_code16(LGUI(KC_K)); break;
case DOUBLE_SINGLE_TAP: unregister_code16(LGUI(KC_L)); break;
}
dance_state[0].step = 0;
}
qk_tap_dance_action_t tap_dance_actions[] = {
[DANCE_0] = ACTION_TAP_DANCE_FN_ADVANCED(on_dance_0, dance_0_finished, dance_0_reset),
};

7
keymaps/default/rules.mk Normal file
View File

@ -0,0 +1,7 @@
# Set any rules.mk overrides for your specific keymap here.
# See rules at https://docs.qmk.fm/#/config_options?id=the-rulesmk-file
LTO_ENABLE = yes
CONSOLE_ENABLE = no
COMMAND_ENABLE = no
TAP_DANCE_ENABLE = yes
SRC = matrix.c

55
led_i2c.c Normal file
View File

@ -0,0 +1,55 @@
/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
Copyright 2015 ZSA Technology Labs Inc (@zsa)
Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
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/>.
*/
#ifdef RGBLIGHT_ENABLE
# include "betalupi_ergodox.h"
void rgblight_call_driver(LED_TYPE *led, uint8_t led_num) {
i2c_init();
i2c_start(0x84, ERGODOX_EZ_I2C_TIMEOUT);
int i = 0;
# if defined(ERGODOX_LED_30)
// prevent right-half code from trying to bitbang all 30
// so with 30 LEDs, we count from 29 to 15 here, and the
// other half does 0 to 14.
uint8_t half_led_num = RGBLED_NUM / 2;
for (i = half_led_num + half_led_num - 1; i >= half_led_num; --i)
# elif defined(ERGODOX_LED_15_MIRROR)
for (i = 0; i < led_num; ++i)
# else // ERGDOX_LED_15 non-mirrored
for (i = led_num - 1; i >= 0; --i)
# endif
{
uint8_t *data = (uint8_t *)(led + i);
i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
#ifdef RGBW
i2c_write(*data++, ERGODOX_EZ_I2C_TIMEOUT);
#endif
}
i2c_stop();
ws2812_setleds(led, led_num);
}
#endif // RGBLIGHT_ENABLE

259
matrix.c Normal file
View File

@ -0,0 +1,259 @@
/*
Note for ErgoDox EZ customizers: Here be dragons!
This is not a file you want to be messing with.
All of the interesting stuff for you is under keymaps/ :)
Love, Erez
Copyright 2012 Jun Wako <wakojun@gmail.com>
Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
Copyright 2015 ZSA Technology Labs Inc (@zsa)
Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
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/>.
*/
/*
* scan matrix
*/
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include "wait.h"
#include "action_layer.h"
#include "print.h"
#include "debug.h"
#include "util.h"
#include "matrix.h"
#include "debounce.h"
#include "betalupi_ergodox.h"
/*
* This constant define not debouncing time in msecs, assuming eager_pr.
*
* On Ergodox matrix scan rate is relatively low, because of slow I2C.
* Now it's only 317 scans/second, or about 3.15 msec/scan.
* According to Cherry specs, debouncing time is 5 msec.
*
* However, some switches seem to have higher debouncing requirements, or
* something else might be wrong. (Also, the scan speed has improved since
* that comment was written.)
*/
/* matrix state(1:on, 0:off) */
extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
static matrix_row_t read_cols(uint8_t row);
static void init_cols(void);
static void unselect_rows(void);
static void select_row(uint8_t row);
static uint8_t mcp23018_reset_loop;
void matrix_init_custom(void) {
// initialize row and col
mcp23018_status = init_mcp23018();
unselect_rows();
init_cols();
}
// Reads and stores a row, returning
// whether a change occurred.
static inline bool store_raw_matrix_row(uint8_t index) {
matrix_row_t temp = read_cols(index);
if (raw_matrix[index] != temp) {
raw_matrix[index] = temp;
return true;
}
return false;
}
bool matrix_scan_custom(matrix_row_t current_matrix[]) {
if (mcp23018_status) { // if there was an error
if (++mcp23018_reset_loop == 0) {
print("trying to reset mcp23018\n");
mcp23018_status = init_mcp23018();
if (mcp23018_status) {
print("left side not responding\n");
} else {
print("left side attached\n");
ergodox_blink_all_leds();
#ifdef RGB_MATRIX_ENABLE
rgb_matrix_init(); // re-init driver on reconnect
#endif
}
}
}
#ifdef LEFT_LEDS
mcp23018_status = ergodox_left_leds_update();
#endif // LEFT_LEDS
bool changed = false;
for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
// select rows from left and right hands
uint8_t left_index = i;
uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
select_row(left_index);
select_row(right_index);
changed |= store_raw_matrix_row(left_index);
changed |= store_raw_matrix_row(right_index);
unselect_rows();
}
return changed;
}
/* Column pin configuration
*
* Teensy
* col: 0 1 2 3 4 5
* pin: F0 F1 F4 F5 F6 F7
*
* MCP23018
* col: 0 1 2 3 4 5
* pin: B5 B4 B3 B2 B1 B0
*/
static void init_cols(void) {
// init on mcp23018
// not needed, already done as part of init_mcp23018()
// init on teensy
setPinInputHigh(F0);
setPinInputHigh(F1);
setPinInputHigh(F4);
setPinInputHigh(F5);
setPinInputHigh(F6);
setPinInputHigh(F7);
}
static matrix_row_t read_cols(uint8_t row) {
if (row < 7) {
if (mcp23018_status) { // if there was an error
return 0;
} else {
uint8_t data = 0;
// reading GPIOB (column port) since in mcp23018's sequential mode
// it is addressed directly after writing to GPIOA in select_row()
mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status < 0) goto out;
data = ~((uint8_t)mcp23018_status);
mcp23018_status = I2C_STATUS_SUCCESS;
out:
i2c_stop();
return data;
}
} else {
/* read from teensy
* bitmask is 0b11110011, but we want those all
* in the lower six bits.
* we'll return 1s for the top two, but that's harmless.
*/
return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
}
}
/* Row pin configuration
*
* Teensy
* row: 7 8 9 10 11 12 13
* pin: B0 B1 B2 B3 D2 D3 C6
*
* MCP23018
* row: 0 1 2 3 4 5 6
* pin: A0 A1 A2 A3 A4 A5 A6
*/
static void unselect_rows(void) {
// no need to unselect on mcp23018, because the select step sets all
// the other row bits high, and it's not changing to a different
// direction
// unselect on teensy
setPinInput(B0);
setPinInput(B1);
setPinInput(B2);
setPinInput(B3);
setPinInput(D2);
setPinInput(D3);
setPinInput(C6);
}
static void select_row(uint8_t row) {
if (row < 7) {
// select on mcp23018
if (!mcp23018_status) {
// set active row low : 0
// set other rows hi-Z : 1
mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0xFF & ~(1 << row), ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
out:
i2c_stop();
}
} else {
// select on teensy
// Output low(DDR:1, PORT:0) to select
switch (row) {
case 7:
setPinOutput(B0);
writePinLow(B0);
break;
case 8:
setPinOutput(B1);
writePinLow(B1);
break;
case 9:
setPinOutput(B2);
writePinLow(B2);
break;
case 10:
setPinOutput(B3);
writePinLow(B3);
break;
case 11:
setPinOutput(D2);
writePinLow(D2);
break;
case 12:
setPinOutput(D3);
writePinLow(D3);
break;
case 13:
setPinOutput(C6);
writePinLow(C6);
break;
}
}
}
// DO NOT REMOVE
// Needed for proper wake/sleep
void matrix_power_up(void) {
mcp23018_status = init_mcp23018();
unselect_rows();
init_cols();
// initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
matrix[i] = 0;
}
}

40
post_config.h Normal file
View File

@ -0,0 +1,40 @@
/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
Copyright 2015 ZSA Technology Labs Inc (@zsa)
Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
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/>.
*/
#pragma once
#if !defined(ERGODOX_LED_15) && !defined(ERGODOX_LED_30)
// if no value is defined, assume previous behavior
// # define ERGODOX_LED_15
// # define ERGODOX_LED_30
# define ERGODOX_LED_15_MIRROR
#endif
#if (defined(ERGODOX_LED_30) + defined(ERGODOX_LED_15) + defined(ERGODOX_LED_15_MIRROR)) != 1
# error "You must only define one of the ERGODOX_LED options."
#endif
#ifdef ERGODOX_LED_30
// If using 30 LEDs, then define that many
# define RGBLED_NUM 30 // Number of LEDs
#else
// If not, then only define 15
# define RGBLED_NUM 15 // Number of LEDs
#endif

48
readme.md Normal file
View File

@ -0,0 +1,48 @@
# Betalupi Ergodox
This is a modified version of the [ZSA ErgoDox firmware](https://git.betalupi.com/QMK/zsa_firmware), based on the `ergodox_ex/glow` keyboard.
--------------------------------------------------------------------------------
# Setup
Make example for this keyboard (after setting up your build environment):
make betalupi_ergodox: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.
--------------------------------------------------------------------------------
# Notes from ZSA
## Oryx Configuation
If you have `ORYX_CONFIGURATOR` defined in your keymap's `config.h`, this enables a number of the built in options from the Oryx Configurator.
### Indicator LEDs
You can use the `LED_LEVEL` keycode to cycle through the brightness levels for the LEDs on the top right of the keyboard. These settings are saved in eeprom (persistant memory).
Alternatively, you can set the brightness by calling the following functions:
```c
void ergodox_led_all_set(uint8_t level);
void ergodox_right_led_1_set(uint8_t level);
void ergodox_right_led_2_set(uint8_t level);
void ergodox_right_led_3_set(uint8_t level);
```
These settings are not persistent, so you'd need to reset it every time the board starts.
These are on a 0-255 scale
### RGB Matrix Features
If you're using the Smart LED (layer indication) feature from the Oryx Configurator, you want to make sure that you enable these options by adding `#define ORYX_CONFIGURATOR` to your keymap's `config.h`.
This changes the `RGB_TOG` keycode so that it will toggle the lights on and off, in a way that will allow the Smart LEDs to continue to work, even with the rest of the LEDs turned off.
Additionally, a new keycode has been added to toggle the Smart LEDs. Use `TOGGLE_LAYER_COLOR`, if you aren't already.

52
rules.mk Normal file
View File

@ -0,0 +1,52 @@
# MCU name
MCU = atmega32u4
# Bootloader selection
# Teensy halfkay
# Pro Micro caterina
# Atmel DFU atmel-dfu
# LUFA DFU lufa-dfu
# QMK DFU qmk-dfu
# ATmega32A bootloadHID
# ATmega328P USBasp
BOOTLOADER = halfkay
# If you have Left LEDs (see
# https://geekhack.org/index.php?topic=22780.msg873819#msg873819 for
# details), include the following define:
# OPT_DEFS += -DLEFT_LEDS
# Build Options
# comment out to disable the options.
#
BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration
MOUSEKEY_ENABLE = yes # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = no # Console for debug
COMMAND_ENABLE = yes # Commands for debug and configuration
CUSTOM_MATRIX = lite # Custom matrix file for the ErgoDox EZ
NKRO_ENABLE = yes # USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
UNICODE_ENABLE = no # Unicode
SWAP_HANDS_ENABLE= no # Allow swapping hands of keyboard
SLEEP_LED_ENABLE = no
API_SYSEX_ENABLE = no
RGB_MATRIX_ENABLE = no # enable later
RGB_MATRIX_DRIVER = IS31FL3731
DEBOUNCE_TYPE = eager_pr
# project specific files
SRC += matrix.c \
led_i2c.c
QUANTUM_LIB_SRC += i2c_master.c
LAYOUTS = ergodox
MOUSE_SHARED_EP = no
# FROM glow dir
RGB_MATRIX_ENABLE = IS31FL3731
RGB_MATRIX_ENABLE = yes
RGB_MATRIX_DRIVER = IS31FL3731

707
util/compile_keymap.py Normal file
View File

@ -0,0 +1,707 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Compiler for keymap.c files
This script will generate a keymap.c file from a simple
markdown file with a specific layout.
Usage:
python compile_keymap.py INPUT_PATH [OUTPUT_PATH]
"""
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
from __future__ import unicode_literals
import os
import io
import re
import sys
import json
import unicodedata
import collections
import itertools as it
PY2 = sys.version_info.major == 2
if PY2:
chr = unichr
KEYBOARD_LAYOUTS = {
# These map positions in the parsed layout to
# positions in the KEYMAP MATRIX
'ergodox_ez': [
[ 0, 1, 2, 3, 4, 5, 6], [38, 39, 40, 41, 42, 43, 44],
[ 7, 8, 9, 10, 11, 12, 13], [45, 46, 47, 48, 49, 50, 51],
[14, 15, 16, 17, 18, 19 ], [ 52, 53, 54, 55, 56, 57],
[20, 21, 22, 23, 24, 25, 26], [58, 59, 60, 61, 62, 63, 64],
[27, 28, 29, 30, 31 ], [ 65, 66, 67, 68, 69],
[ 32, 33], [70, 71 ],
[ 34], [72 ],
[ 35, 36, 37], [73, 74, 75 ],
]
}
ROW_INDENTS = {
'ergodox_ez': [0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 5, 0, 6, 0, 4, 0]
}
BLANK_LAYOUTS = [
# Compact Layout
"""
.------------------------------------.------------------------------------.
| | | | | | | | | | | | | | |
!-----+----+----+----+----+----------!-----+----+----+----+----+----+-----!
| | | | | | | | | | | | | | |
!-----+----+----+----x----x----! ! !----x----x----+----+----+-----!
| | | | | | |-----!-----! | | | | | |
!-----+----+----+----x----x----! ! !----x----x----+----+----+-----!
| | | | | | | | | | | | | | |
'-----+----+----+----+----+----------'----------+----+----+----+----+-----'
| | | | | | ! | | | | |
'------------------------' '------------------------'
.-----------. .-----------.
| | | ! | |
.-----+-----+-----! !-----+-----+-----.
! ! | | ! | ! !
! ! !-----! !-----! ! !
| | | | ! | | |
'-----------------' '-----------------'
""",
# Wide Layout
"""
.---------------------------------------------. .---------------------------------------------.
| | | | | | | | ! | | | | | | |
!-------+-----+-----+-----+-----+-------------! !-------+-----+-----+-----+-----+-----+-------!
| | | | | | | | ! | | | | | | |
!-------+-----+-----+-----x-----x-----! ! ! !-----x-----x-----+-----+-----+-------!
| | | | | | |-------! !-------! | | | | | |
!-------+-----+-----+-----x-----x-----! ! ! !-----x-----x-----+-----+-----+-------!
| | | | | | | | ! | | | | | | |
'-------+-----+-----+-----+-----+-------------' '-------------+-----+-----+-----+-----+-------'
| | | | | | ! | | | | |
'------------------------------' '------------------------------'
.---------------. .---------------.
| | | ! | |
.-------+-------+-------! !-------+-------+-------.
! ! | | ! | ! !
! ! !-------! !-------! ! !
| | | | ! | | |
'-----------------------' '-----------------------'
""",
]
DEFAULT_CONFIG = {
"keymaps_includes": [
"keymap_common.h",
],
'filler': "-+.'!:x",
'separator': "|",
'default_key_prefix': ["KC_"],
}
SECTIONS = [
'layout_config',
'layers',
]
# Markdown Parsing
ONELINE_COMMENT_RE = re.compile(r"""
^ # comment must be at the start of the line
\s* # arbitrary whitespace
// # start of the comment
(.*) # the comment
$ # until the end of line
""", re.MULTILINE | re.VERBOSE
)
INLINE_COMMENT_RE = re.compile(r"""
([\,\"\[\]\{\}\d]) # anythig that might end a expression
\s+ # comment must be preceded by whitespace
// # start of the comment
\s # and succeded by whitespace
(?:[^\"\]\}\{\[]*) # the comment (except things which might be json)
$ # until the end of line
""", re.MULTILINE | re.VERBOSE)
TRAILING_COMMA_RE = re.compile(r"""
, # the comma
(?:\s*) # arbitrary whitespace
$ # only works if the trailing comma is followed by newline
(\s*) # arbitrary whitespace
([\]\}]) # end of an array or object
""", re.MULTILINE | re.VERBOSE)
def loads(raw_data):
if isinstance(raw_data, bytes):
raw_data = raw_data.decode('utf-8')
raw_data = ONELINE_COMMENT_RE.sub(r"", raw_data)
raw_data = INLINE_COMMENT_RE.sub(r"\1", raw_data)
raw_data = TRAILING_COMMA_RE.sub(r"\1\2", raw_data)
return json.loads(raw_data)
def parse_config(path):
def reset_section():
section.update({
'name': section.get('name', ""),
'sub_name': "",
'start_line': -1,
'end_line': -1,
'code_lines': [],
})
def start_section(line_index, line):
end_section()
if line.startswith("# "):
name = line[2:]
elif line.startswith("## "):
name = line[3:]
else:
name = ""
name = name.strip().replace(" ", "_").lower()
if name in SECTIONS:
section['name'] = name
else:
section['sub_name'] = name
section['start_line'] = line_index
def end_section():
if section['start_line'] >= 0:
if section['name'] == 'layout_config':
config.update(loads("\n".join(
section['code_lines']
)))
elif section['sub_name'].startswith('layer'):
layer_name = section['sub_name']
config['layer_lines'][layer_name] = section['code_lines']
reset_section()
def amend_section(line_index, line):
section['end_line'] = line_index
section['code_lines'].append(line)
config = DEFAULT_CONFIG.copy()
config.update({
'layer_lines': collections.OrderedDict(),
'macro_ids': {'UM'},
'unicode_macros': {},
})
section = {}
reset_section()
with io.open(path, encoding="utf-8") as fh:
for i, line in enumerate(fh):
if line.startswith("#"):
start_section(i, line)
elif line.startswith(" "):
amend_section(i, line[4:])
else:
# TODO: maybe parse description
pass
end_section()
assert 'layout' in config
return config
# header file parsing
IF0_RE = re.compile(r"""
^
#if 0
$.*?
#endif
""", re.MULTILINE | re.DOTALL | re.VERBOSE)
COMMENT_RE = re.compile(r"""
/\*
.*?
\*/"
""", re.MULTILINE | re.DOTALL | re.VERBOSE)
def read_header_file(path):
with io.open(path, encoding="utf-8") as fh:
data = fh.read()
data, _ = COMMENT_RE.subn("", data)
data, _ = IF0_RE.subn("", data)
return data
def regex_partial(re_str_fmt, flags):
def partial(*args, **kwargs):
re_str = re_str_fmt.format(*args, **kwargs)
return re.compile(re_str, flags)
return partial
KEYDEF_REP = regex_partial(r"""
#define
\s
(
(?:{}) # the prefixes
(?:\w+) # the key name
) # capture group end
""", re.MULTILINE | re.DOTALL | re.VERBOSE)
ENUM_RE = re.compile(r"""
(
enum
\s\w+\s
\{
.*? # the enum content
\}
;
) # capture group end
""", re.MULTILINE | re.DOTALL | re.VERBOSE)
ENUM_KEY_REP = regex_partial(r"""
(
{} # the prefixes
\w+ # the key name
) # capture group end
""", re.MULTILINE | re.DOTALL | re.VERBOSE)
def parse_keydefs(config, data):
prefix_options = "|".join(config['key_prefixes'])
keydef_re = KEYDEF_REP(prefix_options)
enum_key_re = ENUM_KEY_REP(prefix_options)
for match in keydef_re.finditer(data):
yield match.groups()[0]
for enum_match in ENUM_RE.finditer(data):
enum = enum_match.groups()[0]
for key_match in enum_key_re.finditer(enum):
yield key_match.groups()[0]
def parse_valid_keys(config, out_path):
basepath = os.path.abspath(os.path.join(os.path.dirname(out_path)))
dirpaths = []
subpaths = []
while len(subpaths) < 6:
path = os.path.join(basepath, *subpaths)
dirpaths.append(path)
dirpaths.append(os.path.join(path, "tmk_core", "common"))
dirpaths.append(os.path.join(path, "quantum"))
subpaths.append('..')
includes = set(config['keymaps_includes'])
includes.add("keycode.h")
valid_keycodes = set()
for dirpath, include in it.product(dirpaths, includes):
include_path = os.path.join(dirpath, include)
if os.path.exists(include_path):
header_data = read_header_file(include_path)
valid_keycodes.update(
parse_keydefs(config, header_data)
)
return valid_keycodes
# Keymap Parsing
def iter_raw_codes(layer_lines, filler, separator):
filler_re = re.compile("[" + filler + " ]")
for line in layer_lines:
line, _ = filler_re.subn("", line.strip())
if not line:
continue
codes = line.split(separator)
for code in codes[1:-1]:
yield code
def iter_indexed_codes(raw_codes, key_indexes):
key_rows = {}
key_indexes_flat = []
for row_index, key_indexes in enumerate(key_indexes):
for key_index in key_indexes:
key_rows[key_index] = row_index
key_indexes_flat.extend(key_indexes)
assert len(raw_codes) == len(key_indexes_flat)
for raw_code, key_index in zip(raw_codes, key_indexes_flat):
# we keep track of the row mostly for layout purposes
yield raw_code, key_index, key_rows[key_index]
LAYER_CHANGE_RE = re.compile(r"""
(DF|TG|MO)\(\d+\)
""", re.VERBOSE)
MACRO_RE = re.compile(r"""
M\(\w+\)
""", re.VERBOSE)
UNICODE_RE = re.compile(r"""
U[0-9A-F]{4}
""", re.VERBOSE)
NON_CODE = re.compile(r"""
^[^A-Z0-9_]$
""", re.VERBOSE)
def parse_uni_code(raw_code):
macro_id = "UC_" + (
unicodedata.name(raw_code)
.replace(" ", "_")
.replace("-", "_")
)
code = "M({})".format(macro_id)
uc_hex = "{:04X}".format(ord(raw_code))
return code, macro_id, uc_hex
def parse_key_code(raw_code, key_prefixes, valid_keycodes):
if raw_code in valid_keycodes:
return raw_code
for prefix in key_prefixes:
code = prefix + raw_code
if code in valid_keycodes:
return code
def parse_code(raw_code, key_prefixes, valid_keycodes):
if not raw_code:
return 'KC_TRNS', None, None
if LAYER_CHANGE_RE.match(raw_code):
return raw_code, None, None
if MACRO_RE.match(raw_code):
macro_id = raw_code[2:-1]
return raw_code, macro_id, None
if UNICODE_RE.match(raw_code):
hex_code = raw_code[1:]
return parse_uni_code(chr(int(hex_code, 16)))
if NON_CODE.match(raw_code):
return parse_uni_code(raw_code)
code = parse_key_code(raw_code, key_prefixes, valid_keycodes)
return code, None, None
def parse_keymap(config, key_indexes, layer_lines, valid_keycodes):
keymap = {}
raw_codes = list(iter_raw_codes(
layer_lines, config['filler'], config['separator']
))
indexed_codes = iter_indexed_codes(raw_codes, key_indexes)
key_prefixes = config['key_prefixes']
for raw_code, key_index, row_index in indexed_codes:
code, macro_id, uc_hex = parse_code(
raw_code, key_prefixes, valid_keycodes
)
# TODO: line numbers for invalid codes
err_msg = "Could not parse key '{}' on row {}".format(
raw_code, row_index
)
assert code is not None, err_msg
# print(repr(raw_code), repr(code), macro_id, uc_hex)
if macro_id:
config['macro_ids'].add(macro_id)
if uc_hex:
config['unicode_macros'][macro_id] = uc_hex
keymap[key_index] = (code, row_index)
return keymap
def parse_keymaps(config, valid_keycodes):
keymaps = collections.OrderedDict()
key_indexes = config.get(
'key_indexes', KEYBOARD_LAYOUTS[config['layout']]
)
# TODO: maybe validate key_indexes
for layer_name, layer_lines, in config['layer_lines'].items():
keymaps[layer_name] = parse_keymap(
config, key_indexes, layer_lines, valid_keycodes
)
return keymaps
# keymap.c output
USERCODE = """
// Runs just one time when the keyboard initializes.
void matrix_init_user(void) {
};
// Runs constantly in the background, in a loop.
void matrix_scan_user(void) {
uint8_t layer = biton32(layer_state);
ergodox_board_led_off();
ergodox_right_led_1_off();
ergodox_right_led_2_off();
ergodox_right_led_3_off();
switch (layer) {
case L1:
ergodox_right_led_1_on();
break;
case L2:
ergodox_right_led_2_on();
break;
case L3:
ergodox_right_led_3_on();
break;
case L4:
ergodox_right_led_1_on();
ergodox_right_led_2_on();
break;
case L5:
ergodox_right_led_1_on();
ergodox_right_led_3_on();
break;
// case L6:
// ergodox_right_led_2_on();
// ergodox_right_led_3_on();
// break;
// case L7:
// ergodox_right_led_1_on();
// ergodox_right_led_2_on();
// ergodox_right_led_3_on();
// break;
default:
ergodox_board_led_off();
break;
}
};
"""
MACROCODE = """
#define UC_MODE_WIN 0
#define UC_MODE_LINUX 1
#define UC_MODE_OSX 2
// TODO: allow default mode to be configured
static uint16_t unicode_mode = UC_MODE_WIN;
uint16_t hextokeycode(uint8_t hex) {{
if (hex == 0x0) {{
return KC_P0;
}}
if (hex < 0xA) {{
return KC_P1 + (hex - 0x1);
}}
return KC_A + (hex - 0xA);
}}
void unicode_action_function(uint16_t hi, uint16_t lo) {{
switch (unicode_mode) {{
case UC_MODE_WIN:
register_code(KC_LALT);
register_code(KC_PPLS);
unregister_code(KC_PPLS);
register_code(hextokeycode((hi & 0xF0) >> 4));
unregister_code(hextokeycode((hi & 0xF0) >> 4));
register_code(hextokeycode((hi & 0x0F)));
unregister_code(hextokeycode((hi & 0x0F)));
register_code(hextokeycode((lo & 0xF0) >> 4));
unregister_code(hextokeycode((lo & 0xF0) >> 4));
register_code(hextokeycode((lo & 0x0F)));
unregister_code(hextokeycode((lo & 0x0F)));
unregister_code(KC_LALT);
break;
case UC_MODE_LINUX:
register_code(KC_LCTL);
register_code(KC_LSFT);
register_code(KC_U);
unregister_code(KC_U);
register_code(hextokeycode((hi & 0xF0) >> 4));
unregister_code(hextokeycode((hi & 0xF0) >> 4));
register_code(hextokeycode((hi & 0x0F)));
unregister_code(hextokeycode((hi & 0x0F)));
register_code(hextokeycode((lo & 0xF0) >> 4));
unregister_code(hextokeycode((lo & 0xF0) >> 4));
register_code(hextokeycode((lo & 0x0F)));
unregister_code(hextokeycode((lo & 0x0F)));
unregister_code(KC_LCTL);
unregister_code(KC_LSFT);
break;
case UC_MODE_OSX:
break;
}}
}}
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {{
if (!record->event.pressed) {{
return MACRO_NONE;
}}
// MACRODOWN only works in this function
switch(id) {{
case UM:
unicode_mode = (unicode_mode + 1) % 2;
break;
{macro_cases}
{unicode_macro_cases}
default:
break;
}}
return MACRO_NONE;
}};
"""
UNICODE_MACRO_TEMPLATE = """
case {macro_id}:
unicode_action_function(0x{hi:02x}, 0x{lo:02x});
break;
""".strip()
def unicode_macro_cases(config):
for macro_id, uc_hex in config['unicode_macros'].items():
hi = int(uc_hex, 16) >> 8
lo = int(uc_hex, 16) & 0xFF
unimacro_keys = ", ".join(
"T({})".format(
"KP_" + digit if digit.isdigit() else digit
) for digit in uc_hex
)
yield UNICODE_MACRO_TEMPLATE.format(
macro_id=macro_id, hi=hi, lo=lo
)
def iter_keymap_lines(keymap, row_indents=None):
col_widths = {}
col = 0
# first pass, figure out the column widths
prev_row_index = None
for code, row_index in keymap.values():
if row_index != prev_row_index:
col = 0
if row_indents:
col = row_indents[row_index]
col_widths[col] = max(len(code), col_widths.get(col, 0))
prev_row_index = row_index
col += 1
# second pass, yield the cell values
col = 0
prev_row_index = None
for key_index in sorted(keymap):
code, row_index = keymap[key_index]
if row_index != prev_row_index:
col = 0
yield "\n"
if row_indents:
for indent_col in range(row_indents[row_index]):
pad = " " * (col_widths[indent_col] - 4)
yield (" /*-*/" + pad)
col = row_indents[row_index]
else:
yield pad
yield " {}".format(code)
if key_index < len(keymap) - 1:
yield ","
# This will be yielded on the next iteration when
# we know that we're not at the end of a line.
pad = " " * (col_widths[col] - len(code))
prev_row_index = row_index
col += 1
def iter_keymap_parts(config, keymaps):
# includes
for include_path in config['keymaps_includes']:
yield '#include "{}"\n'.format(include_path)
yield "\n"
# definitions
for i, macro_id in enumerate(sorted(config['macro_ids'])):
yield "#define {} {}\n".format(macro_id, i)
yield "\n"
for i, layer_name in enumerate(config['layer_lines']):
yield '#define L{0:<3} {0:<5} // {1}\n'.format(i, layer_name)
yield "\n"
# keymaps
yield "const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\n"
for i, layer_name in enumerate(config['layer_lines']):
# comment
layer_lines = config['layer_lines'][layer_name]
prefixed_lines = " * " + " * ".join(layer_lines)
yield "/*\n{} */\n".format(prefixed_lines)
# keymap codes
keymap = keymaps[layer_name]
row_indents = ROW_INDENTS.get(config['layout'])
keymap_lines = "".join(iter_keymap_lines(keymap, row_indents))
yield "[L{0}] = KEYMAP({1}\n),\n".format(i, keymap_lines)
yield "};\n\n"
# macros
yield MACROCODE.format(
macro_cases="",
unicode_macro_cases="\n".join(unicode_macro_cases(config)),
)
# TODO: dynamically create blinking lights
yield USERCODE
def main(argv=sys.argv[1:]):
if not argv or '-h' in argv or '--help' in argv:
print(__doc__)
return 0
in_path = os.path.abspath(argv[0])
if not os.path.exists(in_path):
print("No such file '{}'".format(in_path))
return 1
if len(argv) > 1:
out_path = os.path.abspath(argv[1])
else:
dirname = os.path.dirname(in_path)
out_path = os.path.join(dirname, "keymap.c")
config = parse_config(in_path)
valid_keys = parse_valid_keys(config, out_path)
keymaps = parse_keymaps(config, valid_keys)
with io.open(out_path, mode="w", encoding="utf-8") as fh:
for part in iter_keymap_parts(config, keymaps):
fh.write(part)
if __name__ == '__main__':
sys.exit(main())

3
util/readme.md Normal file
View File

@ -0,0 +1,3 @@
# ErgoDox EZ Utilities
The Python script in this directory, by [mbarkhau](https://github.com/mbarkhau) allows you to write out a basic ErgoDox EZ keymap using Markdown notation, and then transpile it to C, which you can then compile. It's experimental, but if you're not comfortable using C, it's a nice option.