[Keyboard] Georgi Support (#5384)

* Working on chording

* Working on chording

* Got layouts in order

* Initial Georgi support

* forgot to add keymaps

* Updated readme

* Update keyboards/georgi/keymaps/template/readme.md

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/georgi.h

Co-Authored-By: germ <jeremythegeek@gmail.com>

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

Co-Authored-By: germ <jeremythegeek@gmail.com>

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

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/rules.mk

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/rules.mk

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/matrix.c

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/georgi.c

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/georgi.c

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/rules.mk

Co-Authored-By: germ <jeremythegeek@gmail.com>

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

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/keymaps/template/keymap.c

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/matrix.c

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Disabled features, updated info

* Update keyboards/georgi/config.h

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Update keyboards/georgi/config.h

Co-Authored-By: germ <jeremythegeek@gmail.com>

* Fixed info.json
master
Jeremy Bernhardt 2019-03-14 14:59:34 -06:00 committed by Drashna Jaelre
parent 2558372b3f
commit 980a41e904
15 changed files with 1618 additions and 0 deletions

74
keyboards/georgi/config.h Normal file
View File

@ -0,0 +1,74 @@
/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Copy and worked on with love from the EZ team
#pragma once
#include "config_common.h"
/* Defaults */
#define VERSION "Alpha 01: Ted "
#define VERBOSE
#define FORCE_NKRO
#define NO_ACTION_MACRO
#define NO_ACTION_FUNCTION
#define NO_DEBUG
#define NO_ACTION_ONESHOT
#define NO_ACTION_FUNCTION
/* USB Device descriptor parameter */
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x1337
#define DEVICE_VER 0x0001
#define MANUFACTURER g Heavy Industries
#define PRODUCT Georgi
#define DESCRIPTION QMK keyboard firmware for Georgi
/* key matrix size */
#define MATRIX_ROWS 14
#define MATRIX_ROWS_PER_SIDE (MATRIX_ROWS / 2)
#define MATRIX_COLS 4
#define MOUSEKEY_INTERVAL 20
#define MOUSEKEY_DELAY 0
#define MOUSEKEY_TIME_TO_MAX 60
#define MOUSEKEY_MAX_SPEED 7
#define MOUSEKEY_WHEEL_DELAY 0
#define TAPPING_TOGGLE 2
/* 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.)
/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
#define LOCKING_SUPPORT_ENABLE
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE
/* key combination for command */
#define IS_COMMAND() ( \
keyboard_report->mods == (MOD_BIT(KC_LCTL) | MOD_BIT(KC_RCTL)) || \
keyboard_report->mods == (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)) \
)
#define DEBOUNCE 5
#define USB_MAX_POWER_CONSUMPTION 500

68
keyboards/georgi/georgi.c Normal file
View File

@ -0,0 +1,68 @@
#include QMK_KEYBOARD_H
bool i2c_initialized = 0;
i2c_status_t mcp23018_status = 0x20;
void matrix_init_kb(void) {
steno_set_mode(STENO_MODE_GEMINI); // or STENO_MODE_BOLT
// (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 | 1<<6 | 1<<7);
DDRE &= ~(1<<6);
PORTC |= (1<<7);
PORTD |= (1<<5 | 1<<4 | 1<<6 | 1<<7);
PORTE |= (1<<6);
matrix_init_user();
}
uint8_t init_mcp23018(void) {
print("starting init");
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(0b10000000, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b11111111, 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(0b10000000, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b11111111, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
out:
i2c_stop();
// SREG=sreg_prev;
//uprintf("Init %x\n", mcp23018_status);
return mcp23018_status;
}

82
keyboards/georgi/georgi.h Normal file
View File

@ -0,0 +1,82 @@
#pragma once
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "quantum.h"
#include "i2c_master.h"
#include "matrix.h"
extern i2c_status_t mcp23018_status;
#define ERGODOX_EZ_I2C_TIMEOUT 1000
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define CPU_16MHz 0x00
// I2C aliases and register addresses (see "mcp23018.md")
//#define I2C_ADDR 0b0100000
#define I2C_ADDR 0x20
#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
void init_ergodox(void);
uint8_t init_mcp23018(void);
/* ---------- LEFT HAND ----------- ---------- RIGHT HAND ---------- */
#define LAYOUT_georgi( \
L00,L01,L02,L03,L04,L05, R00,R01,R02,R03,R04,R05, \
L10,L11,L12,L13,L14,L15, R10,R11,R12,R13,R14,R15, \
L20,L21,L22, R20,R21,R22) \
\
{ \
{ KC_NO, R00, R10, R21}, \
{ KC_NO, R01, R11, R20}, \
{ KC_NO, R02, R12, R22}, \
{ KC_NO, R03, R13, KC_NO}, \
{ KC_NO, R04, R14, KC_NO}, \
{ KC_NO, R05, R15, KC_NO}, \
{ KC_NO, KC_NO, KC_NO, KC_NO}, \
\
{ KC_NO, L05, L15, L22}, \
{ KC_NO, L04, L14, L21}, \
{ KC_NO, L03, L13, L20}, \
{ KC_NO, L02, L12, KC_NO}, \
{ KC_NO, L01, L11, KC_NO}, \
{ KC_NO, L00, L10, KC_NO}, \
{ KC_NO, KC_NO, KC_NO, KC_NO}, \
\
}
/* ---------- LEFT HAND ----------- ---------- RIGHT HAND ----------
#define LAYOUT_GERGO( \
L00,L01,L02,L03,L04,L05, R00,R01,R02,R03,R04,R05, \
L10,L11,L12,L13,L14,L15,L16, R10,R11,R12,R13,R14,R15,R16, \
L20,L21,L22,L23,L24,L25,L26, R20,R21,R22,R23,R24,R25,R26, \
L31,L32, R33,R34, \
L30, R30, \
L33,L34, R31,R32) \
\
{ \
{ KC_NO, L16, L26, L30}, \
{ L05, L15, L25, L34}, \
{ L04, L14, L24, L33}, \
{ L03, L13, L23, L32}, \
{ L02, L12, L22, L31}, \
{ L01, L11, L21, KC_NO}, \
{ L00, L10, L20, KC_NO}, \
\
{ KC_NO, R10, R20, R30}, \
{ R00, R11, R21, R31}, \
{ R01, R12, R22, R32}, \
{ R02, R13, R23, R33}, \
{ R03, R14, R24, R34}, \
{ R04, R15, R25, KC_NO}, \
{ R05, R16, R26, KC_NO}, \
} */

133
keyboards/georgi/info.json Normal file
View File

@ -0,0 +1,133 @@
{
"keyboard_name": "Georgi",
"url": "http://gboards.ca",
"maintainer": "germ",
"width": 13.2,
"height": 3.68,
"layouts": {
"LAYOUT_georgi": {
"layout": [
{
"x": 0.05,
"y": 0.54
},
{
"x": 1.06,
"y": 0.55
},
{
"x": 2.06,
"y": 0.29
},
{
"x": 3.05,
"y": 0.16
},
{
"x": 4.06,
"y": 0.41
},
{
"x": 5.06,
"y": 0.54
},
{
"x": 7.1899999999999995,
"y": 0.41
},
{
"x": 8.2,
"y": 0.3
},
{
"x": 9.2,
"y": 0.05
},
{
"x": 10.2,
"y": 0.29
},
{
"x": 11.2,
"y": 0.43
},
{
"x": 12.2,
"y": 0.42
},
{
"x": 0.05,
"y": 1.54
},
{
"x": 1.06,
"y": 1.54
},
{
"x": 2.06,
"y": 1.28
},
{
"x": 3.05,
"y": 1.16
},
{
"x": 4.06,
"y": 1.4
},
{
"x": 5.06,
"y": 1.54
},
{
"x": 7.1899999999999995,
"y": 1.4
},
{
"x": 8.2,
"y": 1.28
},
{
"x": 9.2,
"y": 1.04
},
{
"x": 10.2,
"y": 1.28
},
{
"x": 11.2,
"y": 1.42
},
{
"x": 12.2,
"y": 1.42
},
{
"x": 3.05,
"y": 2.67
},
{
"x": 4.06,
"y": 2.68
},
{
"x": 5.06,
"y": 2.68
},
{
"x": 7.19,
"y": 2.67
},
{
"x": 8.2,
"y": 2.67
},
{
"x": 9.2,
"y": 2.66
}
]
}
}
}

View File

@ -0,0 +1,229 @@
/*
* Good on you for modifying your layout, this is the most nonQMK layout you will come across
* There are three modes, Steno (the default), QWERTY (Toggleable) and a Momentary symbol layer
*
* Don't modify the steno layer directly, instead add chords using the keycodes and macros
* from sten.h to the layout you want to modify.
*
* Observe the comment above processQWERTY!
*
* http://docs.gboards.ca
*/
#include QMK_KEYBOARD_H
#include "sten.h"
#include "keymap_steno.h"
#define IGNORE_MOD_TAP_INTERRUPT
int getKeymapCount(void);
// Proper Layers
#define FUNCT (LSD | LK | LP | LH)
#define MEDIA (LSD | LK | LW | LR)
#define MOVE (ST1 | ST2)
/* Keyboard Layout
* ,---------------------------------. ,------------------------------.
* | FN | LSU | LFT | LP | LH | ST1 | | ST3 | RF | RP | RL | RT | RD |
* |-----+-----+-----+----+----|-----| |-----|----+----+----+----+----|
* | PWR | LSD | LK | LW | LR | ST2 | | ST4 | RR | RG | RB | RS | RZ |
* `---------------------------------' `------------------------------'
* ,---------------, .---------------.
* | NUM | LA | LO | | RE | RU | NUM |
* `---------------' `---------------'
*/
// YOU MUST ORDER THIS!
// P Will return from processing on the first match it finds. Therefore
// PJ Will run the requested action, remove the matched chord and continue
//
// First any chords that would conflict with PJs need to be checked, then PJs, lastly Ps.
// For all chords should be ordered by length in their section!
//
// http://docs.gboards.ca
bool processQwerty(void) {
// Place P's that would be trashed by PJ's here
P( RT | RS | RD | RZ | NUM, SEND_STRING(VERSION); SEND_STRING(__DATE__));
P( NUM | LA | LO | RE | RU, SEND(KC_MPLY));
P( ST1 | ST2 | ST3 | ST4, SEND(KC_BSPC));
// Thumb Chords
P( LA | LO | RE | RU, SEND(KC_CAPS));
P( LA | RU, SEND(KC_ESC));
PJ( LO | RE, SEND(KC_LCTL));
PJ( NUM | LA | RU, SEND(KC_LCTL); SEND(KC_LSFT));
PJ( NUM | LA | RE, SEND(KC_LCTL); SEND(KC_LSFT); SEND(KC_LALT));
// Mods
PJ( RT | RD | RS | RZ, SEND(KC_LGUI));
PJ( RT | RD, SEND(KC_LCTL));
PJ( RS | RZ, SEND(KC_LALT));
PJ( LA | NUM, SEND(KC_LCTL));
PJ( LA | LO, SEND(KC_LALT));
PJ( LO, SEND(KC_LSFT));
// Function Layer
P( FUNCT | RF | RR, SEND(KC_F5));
P( FUNCT | RP | RB, SEND(KC_F6));
P( FUNCT | RL | RG, SEND(KC_F7));
P( FUNCT | RT | RS, SEND(KC_F8));
P( FUNCT | RF, SEND(KC_F1));
P( FUNCT | RP, SEND(KC_F2));
P( FUNCT | RL, SEND(KC_F3));
P( FUNCT | RT, SEND(KC_F4));
P( FUNCT | RR, SEND(KC_F9));
P( FUNCT | RG, SEND(KC_F10));
P( FUNCT | RB, SEND(KC_F11));
P( FUNCT | RS, SEND(KC_F12));
// Movement Layer
P( MOVE | RF, SEND(KC_LEFT));
P( MOVE | RP, SEND(KC_DOWN));
P( MOVE | RL, SEND(KC_UP));
P( MOVE | RT, SEND(KC_RIGHT));
P( MOVE | ST3, SEND(KC_PGUP));
P( MOVE | ST4, SEND(KC_PGDN));
// Media Layer
P( MEDIA | RF, SEND(KC_MPRV));
P( MEDIA | RP, SEND(KC_MPLY));
P( MEDIA | RL, SEND(KC_MPLY));
P( MEDIA | RT, SEND(KC_MNXT));
P( MEDIA | RD, SEND(KC_VOLU));
P( MEDIA | RZ, SEND(KC_VOLD));
P( MEDIA | RS, SEND(KC_MUTE));
// Mouse Keys
P( LP | LH, clickMouse(KC_MS_BTN1));
P( LW | LR, clickMouse(KC_MS_BTN2));
// Number Row
P( NUM | LSU, SEND(KC_1));
P( NUM | LFT, SEND(KC_2));
P( NUM | LP, SEND(KC_3));
P( NUM | LH, SEND(KC_4));
P( NUM | ST1, SEND(KC_5));
P( NUM | ST3, SEND(KC_6));
P( NUM | RF, SEND(KC_7));
P( NUM | RP, SEND(KC_8));
P( NUM | RL, SEND(KC_9));
P( NUM | RT, SEND(KC_0));
P( NUM | LA, SEND(KC_5));
P( NUM | RT, SEND(KC_0));
// Specials
P( LA | NUM, SEND(KC_ESC));
P( RU | NUM, SEND(KC_TAB));
P( RE | RU, SEND(KC_BSPC));
P( RD | RZ, SEND(KC_ENT));
P( RE, SEND(KC_ENT));
P( RD, SEND(KC_BSPC));
P( NUM, SEND(KC_BSPC));
P( LA, SEND(KC_SPC));
P( RU, SEND(KC_SPC));
P( RZ, SEND(KC_ESC));
// Letters
P( LSU | LSD, SEND(KC_A));
P( LFT | LK, SEND(KC_S));
P( LP | LW, SEND(KC_D));
P( LH | LR, SEND(KC_F));
P( ST1 | ST2, SEND(KC_G));
P( ST3 | ST4, SEND(KC_H));
P( RF | RR, SEND(KC_J));
P( RT | RS, SEND(KC_SCLN))
P( RG | RL, SEND(KC_L));
P( RP | RB, SEND(KC_K));
P( LSU, SEND(KC_Q));
P( LSD, SEND(KC_Z));
P( LFT, SEND(KC_W));
P( LK, SEND(KC_X));
P( LP, SEND(KC_E));
P( LW, SEND(KC_C));
P( LH, SEND(KC_R));
P( LR, SEND(KC_V));
P( ST1, SEND(KC_T));
P( ST2, SEND(KC_B));
P( ST3, SEND(KC_Y));
P( ST4, SEND(KC_N));
P( RF, SEND(KC_U));
P( RR, SEND(KC_M));
P( RP, SEND(KC_I));
P( RB, SEND(KC_COMM));
P( RL, SEND(KC_O));
P( RG, SEND(KC_DOT));
P( RT, SEND(KC_P));
P( RS, SEND(KC_SLSH));
// Symbols and Numbers
P( PWR | RE | RU, SEND(KC_ENT));
P( PWR | LA | LO, SEND(KC_SPC));
P( PWR | LP | LW, SEND(KC_LSFT); SEND(KC_9)); // (
P( PWR | LH | LR, SEND(KC_LSFT); SEND(KC_0)); // )
P( PWR | ST1 | ST2, SEND(KC_GRV)); // `
P( PWR | RD | RZ, SEND(KC_ESC));
P( PWR | LSU | LSD, SEND(KC_LSFT); SEND(KC_3)); // #
P( PWR | LFT | LK, SEND(KC_LSFT); SEND(KC_4)); // $
P( PWR | LSU, SEND(KC_LSFT); SEND(KC_1)); // !
P( PWR | LSD, SEND(KC_LSFT); SEND(KC_5)); // %
P( PWR | LFT, SEND(KC_LSFT); SEND(KC_2)); // @
P( PWR | LK, SEND(KC_LSFT); SEND(KC_6)); // ^
P( PWR | LP, SEND(KC_LSFT); SEND(KC_LBRC)); // {
P( PWR | LW, SEND(KC_LBRC));
P( PWR | LH, SEND(KC_LSFT); SEND(KC_RBRC)); // }
P( PWR | LR, SEND(KC_RBRC));
P( PWR | ST1, SEND(KC_LSFT); SEND(KC_BSLS)); // |
P( PWR | ST2, SEND(KC_LSFT); SEND(KC_GRV)); // ~
P( PWR | ST3, SEND(KC_QUOT));
P( PWR | ST4, SEND(KC_LSFT); SEND(KC_QUOT)); // "
P( PWR | RF, SEND(KC_KP_PLUS));
P( PWR | RR, SEND(KC_LSFT); SEND(KC_7)); // &
P( PWR | RP, SEND(KC_MINS));
P( PWR | RB, SEND(KC_EQL));
P( PWR | RL, SEND(KC_SLSH));
P( PWR | RG, SEND(KC_COMM));
P( PWR | RT, SEND(KC_PAST));
P( PWR | RS, SEND(KC_DOT));
P( PWR | RD, SEND(KC_TAB));
P( PWR | LA, SEND(KC_SCLN));
P( PWR | LO, SEND(KC_SLSH));
P( PWR | RE, SEND(KC_SCLN));
P( PWR | RU, SEND(KC_SLSH));
// If we make here, send as a steno chord
// If plover is running we can hook that host side
return false;
}
#define STENO_LAYER 0
#define GAMING 1
#define GAMING_2 2
// "Layers"
// Steno layer should be first in your map.
// When PWR | FN | RR | RG | RB | RS is pressed, the layer is increased to the next map. You must return to STENO_LAYER at the end.
// If you have only a single layer, you must set SINGLELAYER = yes in your rules.mk, otherwise you may experince undefined behaviour
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
// Main layer, everything goes through here
[STENO_LAYER] = LAYOUT_georgi(
STN_FN, STN_S1, STN_TL, STN_PL, STN_HL, STN_ST1, STN_ST3, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR,
STN_PWR, STN_S2, STN_KL, STN_WL, STN_RL, STN_ST2, STN_ST4, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR,
STN_N1, STN_A, STN_O, STN_E, STN_U, STN_N1)
,
// Gaming layer with Numpad, Very limited
[GAMING] = LAYOUT_georgi(
KC_LSFT, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_ENT,
KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_DQUO,
KC_LALT, KC_SPC, LT(GAMING_2, KC_ENT), KC_DEL, KC_ASTR, TO(STENO_LAYER)),
[GAMING_2] = LAYOUT_georgi(
KC_LSFT, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,
KC_LCTL, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_LT, KC_GT, KC_QUES, KC_RSFT,
KC_LALT, KC_SPC, KC_ENT, KC_DEL, KC_ASTR, TO(STENO_LAYER))
};
int getKeymapCount(void) {
return sizeof(keymaps)/sizeof(keymaps[0]);
}

View File

@ -0,0 +1,11 @@
# Georgi QWERTY/Steno firmware
This is the default keymap for Georgi, it's based heavily off of the naps62 ErgoDox and the Gergo layout.
It is both a ergonomic and programmer friendly keymap.
Ideally you should copy this directory and make your changes there. If you come up with a good layout submit a PR!
## Space issues
If you find yourself running out of space for dictionary entries, disabling mousekeys in rules.mk will save
you about 4k for entries!
Get a free 1k by deleting the Gaming layers from the keymap!

View File

@ -0,0 +1,27 @@
#----------------------------------------------------------------------------
# make georgi:extrakey:dfu
# Make sure you have dfu-programmer installed!
#----------------------------------------------------------------------------
#Debug options
VERBOSE = yes
CONSOLE_ENABLE = yes
DEBUG_MATRIX_SCAN_RATE = no
DEBUG_MATRIX = no
KEYBOARD_SHARED_EP = yes
CUSTOM_MATRIX = yes
MOUSEKEY_ENABLE = yes
SINGLE_LAYER = no
# A bunch of stuff that you shouldn't touch unless you
# know what you're doing.
#
# No touchy, capiche?
SRC += matrix.c i2c_master.c
ifeq ($(strip $(DEBUG_MATRIX)), yes)
OPT_DEFS += -DDEBUG_MATRIX
endif
ifeq ($(strip $(SINGLE_LAYER)), yes)
OPT_DEFS += -DSINGLE_LAYER
endif

View File

@ -0,0 +1,216 @@
/*
* Good on you for modifying your layout, this is the most nonQMK layout you will come across
* There are three modes, Steno (the default), QWERTY (Toggleable) and a Momentary symbol layer
*
* Don't modify the steno layer directly, instead add chords using the keycodes and macros
* from sten.h to the layout you want to modify.
*
* Observe the comment above processQWERTY!
*
* http://docs.gboards.ca
*/
#include QMK_KEYBOARD_H
#include "sten.h"
#include "keymap_steno.h"
#define IGNORE_MOD_TAP_INTERRUPT
int getKeymapCount(void);
// Proper Layers
#define FUNCT (LSD | LK | LP | LH)
#define MEDIA (LSD | LK | LW | LR)
#define MOVE (ST1 | ST2)
/* Keyboard Layout
* ,---------------------------------. ,------------------------------.
* | FN | LSU | LFT | LP | LH | ST1 | | ST3 | RF | RP | RL | RT | RD |
* |-----+-----+-----+----+----|-----| |-----|----+----+----+----+----|
* | PWR | LSD | LK | LW | LR | ST2 | | ST4 | RR | RG | RB | RS | RZ |
* `---------------------------------' `------------------------------'
* ,---------------, .---------------.
* | NUM | LA | LO | | RE | RU | NUM |
* `---------------' `---------------'
*/
// YOU MUST ORDER THIS!
// P Will return from processing on the first match it finds. Therefore
// PJ Will run the requested action, remove the matched chord and continue
//
// First any chords that would conflict with PJs need to be checked, then PJs, lastly Ps.
// For all chords should be ordered by length in their section!
//
// http://docs.gboards.ca
bool processQwerty(void) {
// Place P's that would be trashed by PJ's here
P( RT | RS | RD | RZ | NUM, SEND_STRING(VERSION); SEND_STRING(__DATE__));
P( NUM | LA | LO | RE | RU, SEND(KC_MPLY));
P( ST1 | ST2 | ST3 | ST4, SEND(KC_BSPC));
// Thumb Chords
P( LA | LO | RE | RU, SEND(KC_CAPS));
P( LA | RU, SEND(KC_ESC));
PJ( LO | RE, SEND(KC_LCTL));
PJ( NUM | LA | RU, SEND(KC_LCTL); SEND(KC_LSFT));
PJ( NUM | LA | RE, SEND(KC_LCTL); SEND(KC_LSFT); SEND(KC_LALT));
// Mods
PJ( RT | RD | RS | RZ, SEND(KC_LGUI));
PJ( RT | RD, SEND(KC_LCTL));
PJ( RS | RZ, SEND(KC_LALT));
PJ( LA | NUM, SEND(KC_LCTL));
PJ( LA | LO, SEND(KC_LALT));
PJ( LO, SEND(KC_LSFT));
// Function Layer
P( FUNCT | RF | RR, SEND(KC_F5));
P( FUNCT | RP | RB, SEND(KC_F6));
P( FUNCT | RL | RG, SEND(KC_F7));
P( FUNCT | RT | RS, SEND(KC_F8));
P( FUNCT | RF, SEND(KC_F1));
P( FUNCT | RP, SEND(KC_F2));
P( FUNCT | RL, SEND(KC_F3));
P( FUNCT | RT, SEND(KC_F4));
P( FUNCT | RR, SEND(KC_F9));
P( FUNCT | RG, SEND(KC_F10));
P( FUNCT | RB, SEND(KC_F11));
P( FUNCT | RS, SEND(KC_F12));
// Movement Layer
P( MOVE | RF, SEND(KC_LEFT));
P( MOVE | RP, SEND(KC_DOWN));
P( MOVE | RL, SEND(KC_UP));
P( MOVE | RT, SEND(KC_RIGHT));
P( MOVE | ST3, SEND(KC_PGUP));
P( MOVE | ST4, SEND(KC_PGDN));
// Media Layer
P( MEDIA | RF, SEND(KC_MPRV));
P( MEDIA | RP, SEND(KC_MPLY));
P( MEDIA | RL, SEND(KC_MPLY));
P( MEDIA | RT, SEND(KC_MNXT));
P( MEDIA | RD, SEND(KC_VOLU));
P( MEDIA | RZ, SEND(KC_VOLD));
P( MEDIA | RS, SEND(KC_MUTE));
// Mouse Keys
P( LP | LH, clickMouse(KC_MS_BTN1));
P( LW | LR, clickMouse(KC_MS_BTN2));
// Number Row
P( NUM | LSU, SEND(KC_1));
P( NUM | LFT, SEND(KC_2));
P( NUM | LP, SEND(KC_3));
P( NUM | LH, SEND(KC_4));
P( NUM | ST1, SEND(KC_5));
P( NUM | ST3, SEND(KC_6));
P( NUM | RF, SEND(KC_7));
P( NUM | RP, SEND(KC_8));
P( NUM | RL, SEND(KC_9));
P( NUM | RT, SEND(KC_0));
P( NUM | LA, SEND(KC_5));
P( NUM | RT, SEND(KC_0));
// Specials
P( LA | NUM, SEND(KC_ESC));
P( RU | NUM, SEND(KC_TAB));
P( RE | RU, SEND(KC_BSPC));
P( RD | RZ, SEND(KC_ENT));
P( RE, SEND(KC_ENT));
P( RD, SEND(KC_BSPC));
P( NUM, SEND(KC_BSPC));
P( LA, SEND(KC_SPC));
P( RU, SEND(KC_SPC));
P( RZ, SEND(KC_ESC));
// Letters
P( LSU | LSD, SEND(KC_A));
P( LFT | LK, SEND(KC_S));
P( LP | LW, SEND(KC_D));
P( LH | LR, SEND(KC_F));
P( ST1 | ST2, SEND(KC_G));
P( ST3 | ST4, SEND(KC_H));
P( RF | RR, SEND(KC_J));
P( RT | RS, SEND(KC_SCLN))
P( RG | RL, SEND(KC_L));
P( RP | RB, SEND(KC_K));
P( LSU, SEND(KC_Q));
P( LSD, SEND(KC_Z));
P( LFT, SEND(KC_W));
P( LK, SEND(KC_X));
P( LP, SEND(KC_E));
P( LW, SEND(KC_C));
P( LH, SEND(KC_R));
P( LR, SEND(KC_V));
P( ST1, SEND(KC_T));
P( ST2, SEND(KC_B));
P( ST3, SEND(KC_Y));
P( ST4, SEND(KC_N));
P( RF, SEND(KC_U));
P( RR, SEND(KC_M));
P( RP, SEND(KC_I));
P( RB, SEND(KC_COMM));
P( RL, SEND(KC_O));
P( RG, SEND(KC_DOT));
P( RT, SEND(KC_P));
P( RS, SEND(KC_SLSH));
// Symbols and Numbers
P( PWR | RE | RU, SEND(KC_ENT));
P( PWR | LA | LO, SEND(KC_SPC));
P( PWR | LP | LW, SEND(KC_LSFT); SEND(KC_9)); // (
P( PWR | LH | LR, SEND(KC_LSFT); SEND(KC_0)); // )
P( PWR | ST1 | ST2, SEND(KC_GRV)); // `
P( PWR | RD | RZ, SEND(KC_ESC));
P( PWR | LSU | LSD, SEND(KC_LSFT); SEND(KC_3)); // #
P( PWR | LFT | LK, SEND(KC_LSFT); SEND(KC_4)); // $
P( PWR | LSU, SEND(KC_LSFT); SEND(KC_1)); // !
P( PWR | LSD, SEND(KC_LSFT); SEND(KC_5)); // %
P( PWR | LFT, SEND(KC_LSFT); SEND(KC_2)); // @
P( PWR | LK, SEND(KC_LSFT); SEND(KC_6)); // ^
P( PWR | LP, SEND(KC_LSFT); SEND(KC_LBRC)); // {
P( PWR | LW, SEND(KC_LBRC));
P( PWR | LH, SEND(KC_LSFT); SEND(KC_RBRC)); // }
P( PWR | LR, SEND(KC_RBRC));
P( PWR | ST1, SEND(KC_LSFT); SEND(KC_BSLS)); // |
P( PWR | ST2, SEND(KC_LSFT); SEND(KC_GRV)); // ~
P( PWR | ST3, SEND(KC_QUOT));
P( PWR | ST4, SEND(KC_LSFT); SEND(KC_QUOT)); // "
P( PWR | RF, SEND(KC_KP_PLUS));
P( PWR | RR, SEND(KC_LSFT); SEND(KC_7)); // &
P( PWR | RP, SEND(KC_MINS));
P( PWR | RB, SEND(KC_EQL));
P( PWR | RL, SEND(KC_SLSH));
P( PWR | RG, SEND(KC_COMM));
P( PWR | RT, SEND(KC_PAST));
P( PWR | RS, SEND(KC_DOT));
P( PWR | RD, SEND(KC_TAB));
P( PWR | LA, SEND(KC_SCLN));
P( PWR | LO, SEND(KC_SLSH));
P( PWR | RE, SEND(KC_SCLN));
P( PWR | RU, SEND(KC_SLSH));
// If we make here, send as a steno chord
// If plover is running we can hook that host side
return false;
}
#define STENO_LAYER 0
// "Layers"
// Steno layer should be first in your map.
// When PWR | FN | RR | RG | RB | RS is pressed, the layer is increased to the next map. You must return to STENO_LAYER at the end.
// If you have only a single layer, you must set SINGLELAYER = yes in your rules.mk, otherwise you may experince undefined behaviour
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
// Main layer, everything goes through here
[STENO_LAYER] = LAYOUT_georgi(
STN_FN, STN_S1, STN_TL, STN_PL, STN_HL, STN_ST1, STN_ST3, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR,
STN_PWR, STN_S2, STN_KL, STN_WL, STN_RL, STN_ST2, STN_ST4, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR,
STN_N1, STN_A, STN_O, STN_E, STN_U, STN_N1)
};
int getKeymapCount(void) {
return sizeof(keymaps)/sizeof(keymaps[0]);
}

View File

@ -0,0 +1,6 @@
# Georgi QWERTY/Steno firmware
This is a blank template configured with 5K of free space for your onboard dictionary!
Read the docs over at [gBoards](http://docs.gboards.ca)
Ideally you should copy this directory and make your changes there. If you come up with a good layout submit a PR!

View File

@ -0,0 +1,27 @@
#----------------------------------------------------------------------------
# make georgi:extrakey:dfu
# Make sure you have dfu-programmer installed!
#----------------------------------------------------------------------------
#Debug options
VERBOSE = yes
CONSOLE_ENABLE = yes
DEBUG_MATRIX_SCAN_RATE = no
DEBUG_MATRIX = no
KEYBOARD_SHARED_EP = yes
CUSTOM_MATRIX = yes
MOUSEKEY_ENABLE = no
SINGLE_LAYER = no
# A bunch of stuff that you shouldn't touch unless you
# know what you're doing.
#
# No touchy, capiche?
SRC += matrix.c i2c_master.c
ifeq ($(strip $(DEBUG_MATRIX)), yes)
OPT_DEFS += -DDEBUG_MATRIX
endif
ifeq ($(strip $(SINGLE_LAYER)), yes)
OPT_DEFS += -DSINGLE_LAYER
endif

402
keyboards/georgi/matrix.c Normal file
View File

@ -0,0 +1,402 @@
/*
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 2013 Oleg Kostyuk <cub.uanic@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "matrix.h"
#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 "keymap_steno.h"
#include QMK_KEYBOARD_H
#ifdef DEBUG_MATRIX_SCAN_RATE
#include "timer.h"
#endif
#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif
// MCP Pin Defs
#define RROW1 (1<<3)
#define RROW2 (1<<2)
#define RROW3 (1<<1)
#define RROW4 (1<<0)
#define COL0 (1<<0)
#define COL1 (1<<1)
#define COL2 (1<<2)
#define COL3 (1<<3)
#define COL4 (1<<4)
#define COL5 (1<<5)
#define COL6 (1<<6)
// ATmega pin defs
#define ROW1 (1<<6)
#define ROW2 (1<<5)
#define ROW3 (1<<4)
#define ROW4 (1<<1)
#define COL7 (1<<0)
#define COL8 (1<<1)
#define COL9 (1<<2)
#define COL10 (1<<3)
#define COL11 (1<<2)
#define COL12 (1<<3)
#define COL13 (1<<6)
// bit masks
#define BMASK (COL7 | COL8 | COL9 | COL10)
#define CMASK (COL13)
#define DMASK (COL11 | COL12)
#define FMASK (ROW1 | ROW2 | ROW3 | ROW4)
#define RROWMASK (RROW1 | RROW2 | RROW3 | RROW4)
#define MCPMASK (COL0 | COL1 | COL2 | COL3 | COL4 | COL5 | COL6)
/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
/*
* matrix state(1:on, 0:off)
* contains the raw values without debounce filtering of the last read cycle.
*/
static matrix_row_t raw_matrix[MATRIX_ROWS];
// Debouncing: store for each key the number of scans until it's eligible to
// change. When scanning the matrix, ignore any changes in keys that have
// already changed in the last DEBOUNCE scans.
static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS];
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;
// static uint16_t mcp23018_reset_loop;
#ifdef DEBUG_MATRIX_SCAN_RATE
uint32_t matrix_timer;
uint32_t matrix_scan_count;
#endif
__attribute__ ((weak))
void matrix_init_user(void) {}
__attribute__ ((weak))
void matrix_scan_user(void) {}
__attribute__ ((weak))
void matrix_init_kb(void) {
matrix_init_user();
}
__attribute__ ((weak))
void matrix_scan_kb(void) {
matrix_scan_user();
}
inline
uint8_t matrix_rows(void)
{
return MATRIX_ROWS;
}
inline
uint8_t matrix_cols(void)
{
return MATRIX_COLS;
}
void matrix_init(void)
{
// initialize row and col
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;
raw_matrix[i] = 0;
for (uint8_t j=0; j < MATRIX_COLS; ++j) {
debounce_matrix[i * MATRIX_COLS + j] = 0;
}
}
#ifdef DEBUG_MATRIX_SCAN_RATE
matrix_timer = timer_read32();
matrix_scan_count = 0;
#endif
matrix_init_quantum();
}
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;
}
#ifdef DEBUG_MATRIX_SCAN_RATE
matrix_timer = timer_read32();
matrix_scan_count = 0;
#endif
}
// Returns a matrix_row_t whose bits are set if the corresponding key should be
// eligible to change in this scan.
matrix_row_t debounce_mask(matrix_row_t rawcols, uint8_t row) {
matrix_row_t result = 0;
matrix_row_t change = rawcols ^ raw_matrix[row];
raw_matrix[row] = rawcols;
for (uint8_t i = 0; i < MATRIX_COLS; ++i) {
if (debounce_matrix[row * MATRIX_COLS + i]) {
--debounce_matrix[row * MATRIX_COLS + i];
} else {
result |= (1 << i);
}
if (change & (1 << i)) {
debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE;
}
}
return result;
}
matrix_row_t debounce_read_cols(uint8_t row) {
// Read the row without debouncing filtering and store it for later usage.
matrix_row_t cols = read_cols(row);
// Get the Debounce mask.
matrix_row_t mask = debounce_mask(cols, row);
// debounce the row and return the result.
return (cols & mask) | (matrix[row] & ~mask);;
}
uint8_t matrix_scan(void)
{
// Then the keyboard
if (mcp23018_status) { // if there was an error
if (++mcp23018_reset_loop == 0) {
// if (++mcp23018_reset_loop >= 1300) {
// since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
// this will be approx bit more frequent than once per second
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");
}
}
}
#ifdef DEBUG_MATRIX_SCAN_RATE
matrix_scan_count++;
uint32_t timer_now = timer_read32();
if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
print("matrix scan frequency: ");
pdec(matrix_scan_count);
print("\n");
matrix_timer = timer_now;
matrix_scan_count = 0;
}
#endif
for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
select_row(i);
// and select on left hand
select_row(i + MATRIX_ROWS_PER_SIDE);
// we don't need a 30us delay anymore, because selecting a
// left-hand row requires more than 30us for i2c.
// grab cols from left hand
matrix[i] = debounce_read_cols(i);
// grab cols from right hand
matrix[i + MATRIX_ROWS_PER_SIDE] = debounce_read_cols(i + MATRIX_ROWS_PER_SIDE);
unselect_rows();
}
matrix_scan_quantum();
#ifdef DEBUG_MATRIX
for (uint8_t c = 0; c < MATRIX_COLS; c++)
for (uint8_t r = 0; r < MATRIX_ROWS; r++)
if (matrix_is_on(r, c)) xprintf("r:%d c:%d \n", r, c);
#endif
return 1;
}
bool matrix_is_modified(void) // deprecated and evidently not called.
{
return true;
}
inline
bool matrix_is_on(uint8_t row, uint8_t col)
{
return (matrix[row] & ((matrix_row_t)1<<col));
}
inline
matrix_row_t matrix_get_row(uint8_t row)
{
return matrix[row];
}
void matrix_print(void)
{
print("\nr/c 0123456789ABCDEF\n");
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
phex(row); print(": ");
pbin_reverse16(matrix_get_row(row));
print("\n");
}
}
uint8_t matrix_key_count(void)
{
uint8_t count = 0;
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
count += bitpop16(matrix[i]);
}
return count;
}
// Remember this means ROWS
static void init_cols(void)
{
// init on mcp23018
// not needed, already done as part of init_mcp23018()
// Input with pull-up(DDR:0, PORT:1)
DDRF &= ~FMASK;
PORTF |= FMASK;
}
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;
mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
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();
#ifdef DEBUG_MATRIX
if (data != 0x00) xprintf("I2C: %d\n", data);
#endif
return data;
}
} else {
/* read from teensy
* bitmask is 0b0111001, but we want the lower four
* we'll return 1s for the top two, but that's harmless.
*/
// So I need to confuckulate all this
//return ~(((PIND & DMASK) >> 1 | ((PINC & CMASK) >> 6) | (PIN)));
//return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
return ~(
(((PINF & ROW4) >> 1)
| ((PINF & (ROW1 | ROW2 | ROW3)) >> 3))
& 0xF);
}
}
// Row pin configuration
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
// Hi-Z(DDR:0, PORT:0) to unselect
DDRB &= ~(BMASK);
PORTB &= ~(BMASK);
DDRC &= ~CMASK;
PORTC &= ~CMASK;
DDRD &= ~DMASK;
PORTD &= ~DMASK;
}
static void select_row(uint8_t row)
{
if (row < 7) {
// select on mcp23018
if (mcp23018_status) { // do nothing on error
} else { // 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 {
// Output low(DDR:1, PORT:0) to select
switch (row) {
case 7:
DDRB |= COL7;
PORTB &= ~COL7;
break;
case 8:
DDRB |= COL8;
PORTB &= ~COL8;
break;
case 9:
DDRB |= COL9;
PORTB &= ~COL9;
break;
case 10:
DDRB |= COL10;
PORTB &= ~COL10;
break;
case 11:
DDRD |= COL11;
PORTD &= ~COL11;
break;
case 12:
DDRD |= COL12;
PORTD &= ~COL12;
break;
case 13:
DDRC |= COL13;
PORTC &= ~COL13;
break;
}
}
}

View File

@ -0,0 +1,29 @@
# Georgi
![Georgi](https://i.imgur.com/3kUpRrj.jpg)
A compact 20% (12x2) Split Keyboard for steno and QWERTY.
[More info on qmk.fm](http://qmk.fm/georgi/)
Keyboard Maintainer: [Jeremy Bernhardt](https://github.com/germ)
Hardware Supported: Georgi
Hardware Availability: [gboards.ca](http://gboards.ca)
## Firmware building
After cloning the QMK repo and installing dfu-programmer build and flash with. Be sure to reset your keyboard!
make georgi:default:dfu
To just test your build with the default keymap
make georgi:default
Build options can be enabled/disabled in keyboards/georgi/keymaps/default/rules.mk . Copy the default directory and make any changes to your layout, if you think they're worth sharing submit a PR!
# Space
The stock firmware uses nearly all of the flash avalible. For custom dictionary modifications, disable mousekeys in your keymaps rules.mk (4K of space) and remove the Gaming layers. I've done this already in the provided keymap 'template'.
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).
## Have an idea? [Reach out to me!](mailto:bernhardtjeremy@gmail.com)

22
keyboards/georgi/rules.mk Normal file
View File

@ -0,0 +1,22 @@
#----------------------------------------------------------------------------
# make georgi:default:dfu
# Make sure you have dfu-programmer installed!
# Do not edit this file! Make a copy of keymaps/default and modify that!
#----------------------------------------------------------------------------
# Source includes
SRC += matrix.c i2c_master.c
# Hardware info
MCU = atmega32u4
F_CPU = 16000000
ARCH = AVR8
BOOTLOADER = atmel-dfu
F_USB = $(F_CPU)
EXTRAFLAGS += -flto
CUSTOM_MATRIX = yes
STENO_ENABLE = yes
EXTRAKEY_ENABLE = yes
CONSOLE_ENABLE = no
COMMAND_ENABLE = no
NKRO_ENABLE = yes

2
keyboards/georgi/sten.c Normal file
View File

@ -0,0 +1,2 @@
#include "sten.h"

290
keyboards/georgi/sten.h Normal file
View File

@ -0,0 +1,290 @@
// 2019, g Heavy Industries
#include QMK_KEYBOARD_H
#include "mousekey.h"
#include "keymap.h"
#include "keymap_steno.h"
// Bitfield representing the current chord
uint32_t cChord = 0;
// See if a given chord is pressed.
// P will return
// PJ will continue processing, removing the found chord
#define P(chord, act) if (cChord == (chord)) { act; return true; }
#define PJ(chord, act) if ((cChord & (chord)) == (chord)) { cChord ^= chord; act; }
// All Steno Codes
// Shift to internal representation
#define STN(n) (1L<<n)
//i.e) S(teno)R(ight)F
enum ORDER {
SFN = 0, SPWR, SST1, SST2, SST3, SST4, SNUM,
SLSU, SLSD, SLT, SLK, SLP, SLW, SLH, SLR, SLA, SLO,
SRE, SRU, SRF, SRR, SRP, SRB, SRL, SRG, SRT, SRS, SRD, SRZ
};
// Break it all out
#define FN STN(SFN)
#define PWR STN(SPWR)
#define ST1 STN(SST1)
#define ST2 STN(SST2)
#define ST3 STN(SST3)
#define ST4 STN(SST4)
#define NUM STN(SNUM) // No distinction between left and right
#define LSU STN(SLSU)
#define LSD STN(SLSD)
#define LFT STN(SLT) // (L)e(F)t (T), preprocessor conflict
#define LK STN(SLK)
#define LP STN(SLP)
#define LW STN(SLW)
#define LH STN(SLH)
#define LR STN(SLR)
#define LA STN(SLA)
#define LO STN(SLO)
#define RE STN(SRE)
#define RU STN(SRU)
#define RF STN(SRF)
#define RR STN(SRR)
#define RP STN(SRP)
#define RB STN(SRB)
#define RL STN(SRL)
#define RG STN(SRG)
#define RT STN(SRT)
#define RS STN(SRS)
#define RD STN(SRD)
#define RZ STN(SRZ)
bool processQwerty(void);
bool processFakeSteno(void);
void clickMouse(uint8_t kc);
void SEND(uint8_t kc);
extern int getKeymapCount(void);
// Mode state
enum MODE { STENO = 0, QWERTY, COMMAND };
enum MODE cMode = STENO;
enum MODE pMode;
bool QWERSTENO = false;
// Command State
#define MAX_CMD_BUF 20
uint8_t CMDBUF[MAX_CMD_BUF];
uint8_t CMDLEN = 0;
// Key Repeat state
bool inChord = false;
uint16_t repTimer = 0;
#define REP_DELAY 300
// Mousekeys state
bool inMouse = false;
int8_t mousePress;
// All processing done at chordUp goes through here
bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) {
// Check for mousekeys, this is release
#ifdef MOUSEKEY_ENABLE
if (inMouse) {
inMouse = false;
mousekey_off(mousePress);
mousekey_send();
}
#endif
// Toggle Serial/QWERTY steno
if (cChord == (PWR | FN | ST1 | ST2)) {
uprintf("Fallback Toggle\n");
QWERSTENO = !QWERSTENO;
goto out;
}
// handle command mode
if (cChord == (PWR | FN | RD | RZ)) {
uprintf("COMMAND Toggle\n");
if (cMode != COMMAND) { // Entering Command Mode
CMDLEN = 0;
pMode = cMode;
cMode = COMMAND;
} else { // Exiting Command Mode
cMode = pMode;
// Press all and release all
for (int i = 0; i < CMDLEN; i++) {
register_code(CMDBUF[i]);
}
clear_keyboard();
}
goto out;
}
// Handle Gaming Toggle,
if (cChord == (PWR | FN | ST2 | ST3) && getKeymapCount() > 1) {
uprintf("Switching to QMK\n");
layer_on(1);
goto out;
}
// Lone FN press, toggle QWERTY
if (cChord == FN) {
(cMode == STENO) ? (cMode = QWERTY) : (cMode = STENO);
goto out;
}
// Check for Plover momentary
if (cMode == QWERTY && (cChord & FN)) {
cChord ^= FN;
goto steno;
}
// Do QWERTY and Momentary QWERTY
if (cMode == QWERTY || (cMode == COMMAND) || (cChord & (FN | PWR))) {
if (cChord & FN) cChord ^= FN;
processQwerty();
goto out;
}
// Fallback NKRO Steno
if (cMode == STENO && QWERSTENO) {
processFakeSteno();
goto out;
}
steno:
// Hey that's a steno chord!
inChord = false;
cChord = 0;
return true;
out:
inChord = false;
clear_keyboard();
cChord = 0;
return false;
}
// Update Chord State
bool process_steno_user(uint16_t keycode, keyrecord_t *record) {
// Everything happens in here when steno keys come in.
// Bail on keyup
if (!record->event.pressed) return true;
// Update key repeat timers
repTimer = timer_read();
inChord = true;
// Switch on the press adding to chord
bool pr = record->event.pressed;
switch (keycode) {
// Mods and stuff
case STN_ST1: pr ? (cChord |= (ST1)): (cChord &= ~(ST1)); break;
case STN_ST2: pr ? (cChord |= (ST2)): (cChord &= ~(ST2)); break;
case STN_ST3: pr ? (cChord |= (ST3)): (cChord &= ~(ST3)); break;
case STN_ST4: pr ? (cChord |= (ST4)): (cChord &= ~(ST4)); break;
case STN_FN: pr ? (cChord |= (FN)) : (cChord &= ~(FN)); break;
case STN_PWR: pr ? (cChord |= (PWR)): (cChord &= ~(PWR)); break;
case STN_N1...STN_N6:
case STN_N7...STN_NC: pr ? (cChord |= (NUM)): (cChord &= ~(NUM)); break;
// All the letter keys
case STN_S1: pr ? (cChord |= (LSU)) : (cChord &= ~(LSU)); break;
case STN_S2: pr ? (cChord |= (LSD)) : (cChord &= ~(LSD)); break;
case STN_TL: pr ? (cChord |= (LFT)) : (cChord &= ~(LFT)); break;
case STN_KL: pr ? (cChord |= (LK)) : (cChord &= ~(LK)); break;
case STN_PL: pr ? (cChord |= (LP)) : (cChord &= ~(LP)); break;
case STN_WL: pr ? (cChord |= (LW)) : (cChord &= ~(LW)); break;
case STN_HL: pr ? (cChord |= (LH)) : (cChord &= ~(LH)); break;
case STN_RL: pr ? (cChord |= (LR)) : (cChord &= ~(LR)); break;
case STN_A: pr ? (cChord |= (LA)) : (cChord &= ~(LA)); break;
case STN_O: pr ? (cChord |= (LO)) : (cChord &= ~(LO)); break;
case STN_E: pr ? (cChord |= (RE)) : (cChord &= ~(RE)); break;
case STN_U: pr ? (cChord |= (RU)) : (cChord &= ~(RU)); break;
case STN_FR: pr ? (cChord |= (RF)) : (cChord &= ~(RF)); break;
case STN_RR: pr ? (cChord |= (RR)) : (cChord &= ~(RR)); break;
case STN_PR: pr ? (cChord |= (RP)) : (cChord &= ~(RP)); break;
case STN_BR: pr ? (cChord |= (RB)) : (cChord &= ~(RB)); break;
case STN_LR: pr ? (cChord |= (RL)) : (cChord &= ~(RL)); break;
case STN_GR: pr ? (cChord |= (RG)) : (cChord &= ~(RG)); break;
case STN_TR: pr ? (cChord |= (RT)) : (cChord &= ~(RT)); break;
case STN_SR: pr ? (cChord |= (RS)) : (cChord &= ~(RS)); break;
case STN_DR: pr ? (cChord |= (RD)) : (cChord &= ~(RD)); break;
case STN_ZR: pr ? (cChord |= (RZ)) : (cChord &= ~(RZ)); break;
}
// Check for key repeat in QWERTY mode
return true;
}
void matrix_scan_user(void) {
// We abuse this for early sending of key
// Key repeat only on QWER/SYMB layers
if (cMode != QWERTY) return;
// Check timers
if (timer_elapsed(repTimer) > REP_DELAY) {
// Process Key for report
processQwerty();
// Send report to host
send_keyboard_report();
repTimer = timer_read();
}
};
// Helpers
bool processFakeSteno(void) {
PJ( LSU, SEND(KC_Q););
PJ( LSD, SEND(KC_A););
PJ( LFT, SEND(KC_W););
PJ( LP, SEND(KC_E););
PJ( LH, SEND(KC_R););
PJ( LK, SEND(KC_S););
PJ( LW, SEND(KC_D););
PJ( LR, SEND(KC_F););
PJ( ST1, SEND(KC_T););
PJ( ST2, SEND(KC_G););
PJ( LA, SEND(KC_C););
PJ( LO, SEND(KC_V););
PJ( RE, SEND(KC_N););
PJ( RU, SEND(KC_M););
PJ( ST3, SEND(KC_Y););
PJ( ST4, SEND(KC_H););
PJ( RF, SEND(KC_U););
PJ( RP, SEND(KC_I););
PJ( RL, SEND(KC_O););
PJ( RT, SEND(KC_P););
PJ( RD, SEND(KC_LBRC););
PJ( RR, SEND(KC_J););
PJ( RB, SEND(KC_K););
PJ( RG, SEND(KC_L););
PJ( RS, SEND(KC_SCLN););
PJ( RZ, SEND(KC_COMM););
PJ( NUM, SEND(KC_1););
return false;
}
void clickMouse(uint8_t kc) {
#ifdef MOUSEKEY_ENABLE
mousekey_on(kc);
mousekey_send();
// Store state for later use
inMouse = true;
mousePress = kc;
#endif
}
void SEND(uint8_t kc) {
// Send Keycode, Does not work for Quantum Codes
if (cMode == COMMAND && CMDLEN < MAX_CMD_BUF) {
uprintf("CMD LEN: %d BUF: %d\n", CMDLEN, MAX_CMD_BUF);
CMDBUF[CMDLEN] = kc;
CMDLEN++;
}
if (cMode != COMMAND) register_code(kc);
return;
}