Merge pull request #461 from keyboardio/hardware/generic-avr

Generic AVR hardware base class
pull/464/head
Jesse Vincent 6 years ago committed by GitHub
commit 608ebad910
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,55 @@
# This stub makefile for a Kaleidoscope example pulls in all the targets
# required to build the example
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
SKETCHBOOK_DIR ?= $(HOME)/Documents/Arduino
PACKAGE_DIR ?= $(HOME)/Library/Arduino15
else
SKETCHBOOK_DIR ?= $(HOME)/Arduino
PACKAGE_DIR ?= $(HOME)/.arduino15
endif
ARDUINO_INSTALLED_ENV=$(shell ls -dt $(PACKAGE_DIR)/packages/keyboardio/hardware/avr 2>/dev/null |head -n 1)
MANUALLY_INSTALLED_ENV=$(shell ls -dt $(SKETCHBOOK_DIR)/hardware/keyboardio/avr 2>/dev/null |head -n 1)
ifneq ("$(wildcard $(ARDUINO_INSTALLED_ENV)/boards.txt)","")
ifneq ("$(wildcard $(MANUALLY_INSTALLED_ENV)/boards.txt)","")
$(info ***************************************************************************)
$(info It appears that you have installed two copies of Kaleidoscope. One copy was)
$(info installed using Arduino's "Board Manager", while the other was installed by)
$(info hand, probably using "git".)
$(info )
$(info This will likely cause some trouble as you try to build keyboard firmware)
$(info using Kaleidoscope. You may want to remove either: )
$(info )
$(info $(PACKAGE_DIR)/packages/keyboardio/ which was installed using Arduino)
$(info )
$(info or)
$(info )
$(info $(SKETCHBOOK_DIR)/hardware/keyboardio/ which was installed by hand.)
$(info )
$(info ***************************************************************************)
$(info )
endif
BOARD_HARDWARE_PATH = $(ARDUINO_INSTALLED_ENV)
KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR ?= build-tools/makefiles/
KALEIDOSCOPE_BUILDER_DIR ?= $(ARDUINO_INSTALLED_ENV)/libraries/Kaleidoscope/bin/
endif
BOARD_HARDWARE_PATH ?= $(SKETCHBOOK_DIR)/hardware
KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR ?= keyboardio/avr/build-tools/makefiles/
include $(BOARD_HARDWARE_PATH)/$(KALEIDOSCOPE_PLUGIN_MAKEFILE_DIR)/rules.mk

@ -17,4 +17,4 @@
*/
#pragma once
#include "kaleidoscope/hardware/Atreus.h"
#include "kaleidoscope/hardware/technomancy/Atreus.h"

@ -0,0 +1,173 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-ATMegaKeyboard -- Base class for some ATMega-based boards
* Copyright (C) 2018 Keyboard.io, Inc
*
* 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, version 3.
*
* 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/>.
*/
#if ARDUINO_AVR_PLANCK || ARDUINO_AVR_ATREUS
#include "Kaleidoscope.h"
#include "kaleidoscope/hardware/ATMegaKeyboard.h"
namespace kaleidoscope {
namespace hardware {
bool ATMegaKeyboard::do_scan_;
uint8_t ATMegaKeyboard::debounce = 3;
void ATMegaKeyboard::setup(void) {
wdt_disable();
for (uint8_t i = 0; i < KeyboardHardware.matrix_columns; i++) {
DDR_INPUT(KeyboardHardware.matrix_col_pins[i]);
ENABLE_PULLUP(KeyboardHardware.matrix_col_pins[i]);
}
for (uint8_t i = 0; i < KeyboardHardware.matrix_rows; i++) {
DDR_OUTPUT(KeyboardHardware.matrix_row_pins[i]);
OUTPUT_HIGH(KeyboardHardware.matrix_row_pins[i]);
}
/* Set up Timer1 for 500usec */
TCCR1B = _BV(WGM13);
TCCR1A = 0;
const uint32_t cycles = (F_CPU / 2000000) * 500;
ICR1 = cycles;
TCCR1B = _BV(WGM13) | _BV(CS10);
TIMSK1 = _BV(TOIE1);
}
void ATMegaKeyboard::detachFromHost() {
UDCON |= _BV(DETACH);
}
void ATMegaKeyboard::attachToHost() {
UDCON &= ~_BV(DETACH);
}
void ATMegaKeyboard::readMatrix(void) {
for (uint8_t current_row = 0; current_row < KeyboardHardware.matrix_rows; current_row++) {
uint16_t mask, cols;
KeyboardHardware.previousKeyState_[current_row] = KeyboardHardware.keyState_[current_row];
mask = KeyboardHardware.debounceMaskForRow(current_row);
OUTPUT_TOGGLE(KeyboardHardware.matrix_row_pins[current_row]);
cols = (KeyboardHardware.readCols() & mask) | (KeyboardHardware.keyState_[current_row] & ~mask);
OUTPUT_TOGGLE(KeyboardHardware.matrix_row_pins[current_row]);
KeyboardHardware.debounceRow(cols ^ KeyboardHardware.keyState_[current_row], current_row);
KeyboardHardware.keyState_[current_row] = cols;
}
}
uint8_t ATMegaKeyboard::pressedKeyswitchCount() {
uint8_t count = 0;
for (int8_t r = 0; r < KeyboardHardware.matrix_rows; r++) {
count += __builtin_popcount(KeyboardHardware.keyState_[r]);
}
return count;
}
bool ATMegaKeyboard::isKeyswitchPressed(uint8_t row, byte col) {
return (bitRead(KeyboardHardware.keyState_[row], col) != 0);
}
bool ATMegaKeyboard::isKeyswitchPressed(uint8_t keyIndex) {
keyIndex--;
return isKeyswitchPressed(keyIndex / KeyboardHardware.matrix_columns,
keyIndex % KeyboardHardware.matrix_columns);
}
void ATMegaKeyboard::actOnMatrixScan() {
for (byte row = 0; row < KeyboardHardware.matrix_rows; row++) {
for (byte col = 0; col < KeyboardHardware.matrix_columns; col++) {
uint8_t keyState = (bitRead(KeyboardHardware.previousKeyState_[row], col) << 0) |
(bitRead(KeyboardHardware.keyState_[row], col) << 1);
if (keyState) {
handleKeyswitchEvent(Key_NoKey, row, col, keyState);
}
}
KeyboardHardware.previousKeyState_[row] = KeyboardHardware.keyState_[row];
}
}
void ATMegaKeyboard::scanMatrix() {
if (!do_scan_)
return;
do_scan_ = false;
KeyboardHardware.readMatrix();
KeyboardHardware.actOnMatrixScan();
}
void ATMegaKeyboard::maskKey(byte row, byte col) {
if (row >= KeyboardHardware.matrix_rows || col >= KeyboardHardware.matrix_columns)
return;
bitWrite(KeyboardHardware.masks_[row], col, 1);
}
void ATMegaKeyboard::unMaskKey(byte row, byte col) {
if (row >= KeyboardHardware.matrix_rows || col >= KeyboardHardware.matrix_columns)
return;
bitWrite(KeyboardHardware.masks_[row], col, 0);
}
bool ATMegaKeyboard::isKeyMasked(byte row, byte col) {
if (row >= KeyboardHardware.matrix_rows || col >= KeyboardHardware.matrix_columns)
return false;
return bitRead(KeyboardHardware.masks_[row], col);
}
uint16_t ATMegaKeyboard::readCols() {
uint16_t results = 0x00 ;
for (uint8_t i = 0; i < KeyboardHardware.matrix_columns; i++) {
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[i]) << i);
}
return results;
}
uint16_t ATMegaKeyboard::debounceMaskForRow(uint8_t row) {
uint16_t result = 0;
for (uint16_t c = 0; c < KeyboardHardware.matrix_columns; ++c) {
if (KeyboardHardware.debounce_matrix_[row][c]) {
--KeyboardHardware.debounce_matrix_[row][c];
} else {
result |= _BV(c);
}
}
return result;
}
void ATMegaKeyboard::debounceRow(uint16_t change, uint8_t row) {
for (uint16_t i = 0; i < KeyboardHardware.matrix_columns; ++i) {
if (change & _BV(i)) {
KeyboardHardware.debounce_matrix_[row][i] = debounce;
}
}
}
}
}
#endif

@ -0,0 +1,162 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-ATMegaKeyboard -- Base class for some ATMega-based boards
* Copyright (C) 2018 Keyboard.io, Inc
*
* 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, version 3.
*
* 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 ARDUINO_AVR_PLANCK || ARDUINO_AVR_ATREUS
#include <Arduino.h>
#include <KeyboardioHID.h>
#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h"
#include "kaleidoscope/macro_helpers.h"
#include "kaleidoscope/key_events.h"
#include "kaleidoscope/hardware/avr/pins_and_ports.h"
#include <avr/wdt.h>
struct cRGB {
uint8_t r, g, b;
};
#define CRGB(r,g,b) (cRGB){b, g, r}
#define ROW_PIN_LIST(...) __VA_ARGS__
#define COL_PIN_LIST(...) __VA_ARGS__
#define ATMEGA_KEYBOARD_CONFIG(ROW_PINS_, COL_PINS_) \
static const int8_t matrix_rows = NUM_ARGS(ROW_PINS_); \
static const int8_t matrix_columns = NUM_ARGS(COL_PINS_); \
static constexpr uint8_t matrix_row_pins[matrix_rows] = ROW_PINS_; \
static constexpr uint8_t matrix_col_pins[matrix_columns] = COL_PINS_; \
\
static uint16_t previousKeyState_[matrix_rows]; \
static uint16_t keyState_[matrix_rows]; \
static uint16_t masks_[matrix_rows]; \
static uint8_t debounce_matrix_[matrix_rows][matrix_columns];
#define ATMEGA_KEYBOARD_DATA(BOARD) \
const int8_t BOARD::matrix_rows; \
const int8_t BOARD::matrix_columns; \
constexpr uint8_t BOARD::matrix_row_pins[matrix_rows]; \
constexpr uint8_t BOARD::matrix_col_pins[matrix_columns]; \
uint16_t BOARD::previousKeyState_[matrix_rows]; \
uint16_t BOARD::keyState_[matrix_rows]; \
uint16_t BOARD::masks_[matrix_rows]; \
uint8_t BOARD::debounce_matrix_[matrix_rows][matrix_columns]; \
\
ISR(TIMER1_OVF_vect) { \
BOARD::do_scan_ = true; \
}
namespace kaleidoscope {
namespace hardware {
class ATMegaKeyboard {
public:
ATMegaKeyboard(void) {}
// these will be overridden by the subclass
static uint8_t debounce;
void syncLeds(void) {}
void setCrgbAt(uint8_t row, byte col, cRGB color) {}
void setCrgbAt(int8_t i, cRGB crgb) {}
cRGB getCrgbAt(int8_t i) {
return CRGB(0, 0, 0);
}
int8_t getLedIndex(uint8_t row, byte col) {
return -1;
}
void setup(void);
/** Detaching from / attaching to the host.
*
* These two functions should detach the device from (or attach it to) the
* host, preferably without rebooting the device. Their purpose is to allow
* one to do some configuration inbetween, so the re-attach happens with
* different properties. The device remains powered between these operations,
* only the connection to the host gets severed.
*/
void detachFromHost();
void attachToHost();
void readMatrix(void);
/**
* Check the number of key switches currently pressed.
*
* @returns the number of keys pressed.
*/
uint8_t pressedKeyswitchCount();
/** Key switch states
*
* These methods offer a way to peek at the key switch states, for those cases
* where we need to deal with the state closest to the hardware. Some methods
* offer a way to check if a key is pressed, others return the number of
* pressed keys.
*/
/**
* Check if a key is pressed at a given position.
*
* @param row is the row the key is located at in the matrix.
* @param col is the column the key is located at in the matrix.
*
* @returns true if the key is pressed, false otherwise.
*/
bool isKeyswitchPressed(uint8_t row, byte col);
/**
* Check if a key is pressed at a given position.
*
* @param keyIndex is the key index, as calculated by `keyIndex`.
*
* @note Key indexes start at 1, not 0!
*
* @returns true if the key is pressed, false otherwise.
*/
bool isKeyswitchPressed(uint8_t keyIndex);
void actOnMatrixScan();
void scanMatrix();
/* Key masking
* -----------
*
* There are situations when one wants to ignore key events for a while, and
* mask them out. These functions help do that. In isolation, they do nothing,
* plugins and the core firmware is expected to make use of these.
*
* See `handleKeyswitchEvent` in the Kaleidoscope sources for a use-case.
*/
void maskKey(byte row, byte col);
void unMaskKey(byte row, byte col);
bool isKeyMasked(byte row, byte col);
static bool do_scan_;
private:
uint16_t readCols();
uint16_t debounceMaskForRow(uint8_t row);
void debounceRow(uint16_t change, uint8_t row);
};
}
}
#endif

@ -1,256 +0,0 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Technomancy-Atreus -- Atreus hardware support for Kaleidoscope
* Copyright (C) 2018 Keyboard.io, Inc
*
* Based on QMK (commit e9a67f8fd)
* (C) Jack Humbert, Phil Hagelberg, and others
* Original QMK sources:
* - keyboards/atreus/atreus.h
* - keyboards/atreus/config.h
* - quantum/matrix.c
* - tmk_core/common/avr/bootloader.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef ARDUINO_AVR_ATREUS
#include <Kaleidoscope.h>
#include <KeyboardioHID.h>
#include <avr/wdt.h>
static bool do_scan_ = true;
ISR(TIMER1_OVF_vect) {
do_scan_ = true;
}
namespace kaleidoscope {
namespace hardware {
uint16_t Atreus::previousKeyState_[ROWS];
uint16_t Atreus::keyState_[ROWS];
uint16_t Atreus::masks_[ROWS];
uint8_t Atreus::debounce_matrix_[ROWS][COLS];
uint8_t Atreus::debounce = 3;
constexpr uint8_t Atreus::row_pins[4];
void Atreus::setup(void) {
wdt_disable();
delay(100);
// Initialize rows
DDRD |= _BV(0) | _BV(1) | _BV(3) | _BV(2);
PORTD |= _BV(0) | _BV(1) | _BV(3) | _BV(2);
// Initialize columns
DDRB &= ~(_BV(5) | _BV(4) | _BV(6) | _BV(7));
PORTB |= (_BV(5) | _BV(4) | _BV(6) | _BV(7));
DDRD &= ~(_BV(7) | _BV(4) | _BV(6));
PORTD |= (_BV(7) | _BV(4) | _BV(6));
DDRC &= ~(_BV(6));
PORTC |= (_BV(6));
DDRE &= ~(_BV(6));
PORTE |= (_BV(6));
DDRF &= ~(_BV(6) | _BV(7));
PORTF |= (_BV(6) | _BV(7));
/* Set up Timer1 for 500usec */
TCCR1B = _BV(WGM13);
TCCR1A = 0;
const uint32_t cycles = (F_CPU / 2000000) * 500;
ICR1 = cycles;
TCCR1B = _BV(WGM13) | _BV(CS10);
TIMSK1 = _BV(TOIE1);
}
void Atreus::toggleRow(uint8_t row) {
PORTD ^= _BV(row_pins[row]);
}
uint16_t Atreus::readCols() {
return ((PINB & (_BV(4)) ? 0 : (_BV(0))) |
(PINB & (_BV(5)) ? 0 : (_BV(1))) |
(PINB & (_BV(6)) ? 0 : (_BV(2))) |
(PINB & (_BV(7)) ? 0 : (_BV(3))) |
(PINC & (_BV(6)) ? 0 : (_BV(4))) |
(PIND & (_BV(4)) ? 0 : (_BV(5))) |
(PIND & (_BV(6)) ? 0 : (_BV(6))) |
(PIND & (_BV(7)) ? 0 : (_BV(7))) |
(PINE & (_BV(6)) ? 0 : (_BV(8))) |
(PINF & (_BV(6)) ? 0 : (_BV(9))) |
(PINF & (_BV(7)) ? 0 : (_BV(10))));
}
void Atreus::readMatrixRow(uint8_t current_row) {
uint16_t mask, cols;
previousKeyState_[current_row] = keyState_[current_row];
mask = debounceMaskForRow(current_row);
toggleRow(current_row);
cols = (readCols() & mask) | (keyState_[current_row] & ~mask);
toggleRow(current_row);
debounceRow(cols ^ keyState_[current_row], current_row);
keyState_[current_row] = cols;
}
void Atreus::readMatrix() {
do_scan_ = false;
for (uint8_t current_row = 0; current_row < ROWS; current_row++) {
readMatrixRow(current_row);
}
}
void Atreus::actOnMatrixScan() {
for (byte row = 0; row < ROWS; row++) {
for (byte col = 0; col < COLS; col++) {
uint8_t keyState = (bitRead(previousKeyState_[row], col) << 0) |
(bitRead(keyState_[row], col) << 1);
if (keyState) {
handleKeyswitchEvent(Key_NoKey, row, col, keyState);
}
}
previousKeyState_[row] = keyState_[row];
}
}
void Atreus::scanMatrix() {
if (!do_scan_)
return;
readMatrix();
actOnMatrixScan();
}
void Atreus::maskKey(byte row, byte col) {
if (row >= ROWS || col >= COLS)
return;
bitWrite(masks_[row], col, 1);
}
void Atreus::unMaskKey(byte row, byte col) {
if (row >= ROWS || col >= COLS)
return;
bitWrite(masks_[row], col, 0);
}
bool Atreus::isKeyMasked(byte row, byte col) {
if (row >= ROWS || col >= COLS)
return false;
return bitRead(masks_[row], col);
}
// Atreus-specific stuff
void Atreus::resetDevice() {
cli();
UDCON = 1;
USBCON = (1 << FRZCLK);
UCSR1B = 0;
_delay_ms(5);
EIMSK = 0;
PCICR = 0;
SPCR = 0;
ACSR = 0;
EECR = 0;
ADCSRA = 0;
TIMSK0 = 0;
TIMSK1 = 0;
TIMSK3 = 0;
TIMSK4 = 0;
UCSR1B = 0;
TWCR = 0;
DDRB = 0;
DDRC = 0;
DDRD = 0;
DDRE = 0;
DDRF = 0;
TWCR = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
PORTE = 0;
PORTF = 0;
asm volatile("jmp 0x7E00");
}
void Atreus::detachFromHost() {
UDCON |= (1 << DETACH);
}
void Atreus::attachToHost() {
UDCON &= ~(1 << DETACH);
}
bool Atreus::isKeyswitchPressed(byte row, byte col) {
return (bitRead(keyState_[row], col) != 0);
}
bool Atreus::isKeyswitchPressed(uint8_t keyIndex) {
keyIndex--;
return isKeyswitchPressed(keyIndex / COLS, keyIndex % COLS);
}
uint8_t Atreus::pressedKeyswitchCount() {
uint8_t count = 0;
for (uint8_t r = 0; r < ROWS; r++) {
count += __builtin_popcount(keyState_[r]);
}
return count;
}
uint16_t Atreus::debounceMaskForRow(uint8_t row) {
uint16_t result = 0;
for (uint16_t c = 0; c < COLS; ++c) {
if (debounce_matrix_[row][c]) {
--debounce_matrix_[row][c];
} else {
result |= (1 << c);
}
}
return result;
}
void Atreus::debounceRow(uint16_t change, uint8_t row) {
for (uint16_t i = 0; i < COLS; ++i) {
if (change & (1 << i)) {
debounce_matrix_[row][i] = debounce;
}
}
}
}
}
HARDWARE_IMPLEMENTATION KeyboardHardware;
kaleidoscope::hardware::Atreus &Atreus = KeyboardHardware;
#endif

@ -1,241 +0,0 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Technomancy-Atreus -- Atreus hardware support for Kaleidoscope
* Copyright (C) 2018 Keyboard.io, Inc
*
* Based on QMK (commit e9a67f8fd)
* (C) Jack Humbert, Jun Wako, Phil Hagelberg, and others
* Original QMK sources:
* - keyboards/atreus/atreus.h
* - keyboards/atreus/config.h
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef ARDUINO_AVR_ATREUS
#include <Arduino.h>
#define HARDWARE_IMPLEMENTATION kaleidoscope::hardware::Atreus
#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h"
#include "kaleidoscope/macro_helpers.h"
struct cRGB {
uint8_t r, g, b;
};
#define CRGB(r,g,b) (cRGB){b, g, r}
namespace kaleidoscope {
namespace hardware {
class Atreus {
public:
Atreus(void) {}
static constexpr byte matrix_columns = 11;
static constexpr byte matrix_rows = 4;
static constexpr int8_t led_count = 0;
void syncLeds(void) {}
void setCrgbAt(byte row, byte col, cRGB color) {}
void setCrgbAt(int8_t i, cRGB crgb) {}
cRGB getCrgbAt(int8_t i) {
return CRGB(0, 0, 0);
}
int8_t getLedIndex(byte row, byte col) {
return -1;
}
void scanMatrix(void);
void readMatrix(void);
void actOnMatrixScan(void);
void setup();
/** Detaching from / attaching to the host.
*
* These two functions should detach the device from (or attach it to) the
* host, preferably without rebooting the device. Their purpose is to allow
* one to do some configuration inbetween, so the re-attach happens with
* different properties. The device remains powered between these operations,
* only the connection to the host gets severed.
*/
void detachFromHost();
void attachToHost();
/* Key masking
* -----------
*
* There are situations when one wants to ignore key events for a while, and
* mask them out. These functions help do that. In isolation, they do nothing,
* plugins and the core firmware is expected to make use of these.
*
* See `handleKeyswitchEvent` in the Kaleidoscope sources for a use-case.
*/
void maskKey(byte row, byte col);
void unMaskKey(byte row, byte col);
bool isKeyMasked(byte row, byte col);
/** Key switch states
*
* These methods offer a way to peek at the key switch states, for those cases
* where we need to deal with the state closest to the hardware. Some methods
* offer a way to check if a key is pressed, others return the number of
* pressed keys.
*/
/**
* Check if a key is pressed at a given position.
*
* @param row is the row the key is located at in the matrix.
* @param col is the column the key is located at in the matrix.
*
* @returns true if the key is pressed, false otherwise.
*/
bool isKeyswitchPressed(byte row, byte col);
/**
* Check if a key is pressed at a given position.
*
* @param keyIndex is the key index, as calculated by `keyIndex`.
*
* @note Key indexes start at 1, not 0!
*
* @returns true if the key is pressed, false otherwise.
*/
bool isKeyswitchPressed(uint8_t keyIndex);
/**
* Check the number of key switches currently pressed.
*
* @returns the number of keys pressed.
*/
uint8_t pressedKeyswitchCount();
void resetDevice();
static uint8_t debounce;
private:
static constexpr uint8_t row_pins[4] = {0, 1, 3, 2};
static uint16_t previousKeyState_[matrix_rows];
static uint16_t keyState_[matrix_rows];
static uint16_t masks_[matrix_rows];
static void readMatrixRow(uint8_t row);
static uint16_t readCols();
static void toggleRow(uint8_t row);
static uint8_t debounce_matrix_[matrix_rows][matrix_columns];
static uint16_t debounceMaskForRow(uint8_t row);
static void debounceRow(uint16_t change, uint8_t row);
};
#define KEYMAP( \
R0C0, R0C1, R0C2, R0C3, R0C4, R0C7, R0C8, R0C9, R0C10, R0C11, \
R1C0, R1C1, R1C2, R1C3, R1C4, R1C7, R1C8, R1C9, R1C10, R1C11, \
R2C0, R2C1, R2C2, R2C3, R2C4, R2C7, R2C8, R2C9, R2C10, R2C11, \
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11 \
) \
{ \
{ R0C3, R0C2, R0C7, R0C11, R0C1, XXX, R0C10, R0C0, R0C4, R0C8, R0C9 }, \
{ R1C3, R1C2, R1C7, R1C11, R1C1, XXX, R1C10, R1C0, R1C4, R1C8, R1C9 }, \
{ R2C3, R2C2, R2C7, R2C11, R2C1, R3C5, R2C10, R2C0, R2C4, R2C8, R2C9 }, \
{ R3C3, R3C2, R3C7, R3C11, R3C1, R3C6, R3C10, R3C0, R3C4, R3C8, R3C9 } \
}
#define KEYMAP_STACKED( \
R0C0, R0C1, R0C2, R0C3, R0C4, \
R1C0, R1C1, R1C2, R1C3, R1C4, \
R2C0, R2C1, R2C2, R2C3, R2C4, \
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, \
\
R0C7, R0C8, R0C9, R0C10, R0C11, \
R1C7, R1C8, R1C9, R1C10, R1C11, \
R2C7, R2C8, R2C9, R2C10, R2C11, \
R3C6, R3C7, R3C8, R3C9, R3C10, R3C11 \
) \
{ \
{ R0C3, R0C2, R0C7, R0C11, R0C1, XXX, R0C10, R0C0, R0C4, R0C8, R0C9 }, \
{ R1C3, R1C2, R1C7, R1C11, R1C1, XXX, R1C10, R1C0, R1C4, R1C8, R1C9 }, \
{ R2C3, R2C2, R2C7, R2C11, R2C1, R3C5, R2C10, R2C0, R2C4, R2C8, R2C9 }, \
{ R3C3, R3C2, R3C7, R3C11, R3C1, R3C6, R3C10, R3C0, R3C4, R3C8, R3C9 } \
}
}
}
/* To be used by the hardware implementations, `keyIndex` tells us the index of
* a key, from which we can figure out the row and column as needed. The index
* starts at one, so that plugins that work with a list of key indexes can use
* zero as a sentinel. This is important, because when we initialize arrays with
* fewer elements than the declared array size, the remaining elements will be
* zero. We can use this to avoid having to explicitly add a sentinel in
* user-facing code.
*/
constexpr byte keyIndex(byte row, byte col) {
return row * kaleidoscope::hardware::Atreus::matrix_columns + col + 1;
}
constexpr byte R0C0 = keyIndex(0, 0);
constexpr byte R0C1 = keyIndex(0, 1);
constexpr byte R0C2 = keyIndex(0, 2);
constexpr byte R0C3 = keyIndex(0, 3);
constexpr byte R0C4 = keyIndex(0, 4);
constexpr byte R0C7 = keyIndex(0, 7);
constexpr byte R0C8 = keyIndex(0, 8);
constexpr byte R0C9 = keyIndex(0, 9);
constexpr byte R0C10 = keyIndex(0, 10);
constexpr byte R0C11 = keyIndex(0, 11);
constexpr byte R1C0 = keyIndex(1, 0);
constexpr byte R1C1 = keyIndex(1, 1);
constexpr byte R1C2 = keyIndex(1, 2);
constexpr byte R1C3 = keyIndex(1, 3);
constexpr byte R1C4 = keyIndex(1, 4);
constexpr byte R1C7 = keyIndex(1, 7);
constexpr byte R1C8 = keyIndex(1, 8);
constexpr byte R1C9 = keyIndex(1, 9);
constexpr byte R1C10 = keyIndex(1, 10);
constexpr byte R1C11 = keyIndex(1, 11);
constexpr byte R2C0 = keyIndex(2, 0);
constexpr byte R2C1 = keyIndex(2, 1);
constexpr byte R2C2 = keyIndex(2, 2);
constexpr byte R2C3 = keyIndex(2, 3);
constexpr byte R2C4 = keyIndex(2, 4);
constexpr byte R2C7 = keyIndex(2, 7);
constexpr byte R2C8 = keyIndex(2, 8);
constexpr byte R2C9 = keyIndex(2, 9);
constexpr byte R2C10 = keyIndex(2, 10);
constexpr byte R2C11 = keyIndex(2, 11);
constexpr byte R3C0 = keyIndex(3, 0);
constexpr byte R3C1 = keyIndex(3, 1);
constexpr byte R3C2 = keyIndex(3, 2);
constexpr byte R3C3 = keyIndex(3, 3);
constexpr byte R3C4 = keyIndex(3, 4);
constexpr byte R3C5 = keyIndex(3, 5);
constexpr byte R3C6 = keyIndex(3, 6);
constexpr byte R3C7 = keyIndex(3, 7);
constexpr byte R3C8 = keyIndex(3, 8);
constexpr byte R3C9 = keyIndex(3, 9);
constexpr byte R3C10 = keyIndex(3, 10);
constexpr byte R3C11 = keyIndex(3, 11);
extern kaleidoscope::hardware::Atreus &Atreus;
#endif

@ -187,107 +187,7 @@ class ErgoDox {
}
}
/* To be used by the hardware implementations, `keyIndex` tells us the index of
* a key, from which we can figure out the row and column as needed. The index
* starts at one, so that plugins that work with a list of key indexes can use
* zero as a sentinel. This is important, because when we initialize arrays with
* fewer elements than the declared array size, the remaining elements will be
* zero. We can use this to avoid having to explicitly add a sentinel in
* user-facing code.
*/
constexpr byte keyIndex(byte row, byte col) {
return row * kaleidoscope::hardware::ErgoDox::matrix_columns + col + 1;
}
constexpr byte R0C0 = keyIndex(0, 0);
constexpr byte R0C1 = keyIndex(0, 1);
constexpr byte R0C2 = keyIndex(0, 2);
constexpr byte R0C3 = keyIndex(0, 3);
constexpr byte R0C4 = keyIndex(0, 4);
constexpr byte R0C5 = keyIndex(0, 5);
constexpr byte R0C6 = keyIndex(0, 6);
constexpr byte R0C7 = keyIndex(0, 7);
constexpr byte R0C8 = keyIndex(0, 8);
constexpr byte R0C9 = keyIndex(0, 9);
constexpr byte R0C10 = keyIndex(0, 10);
constexpr byte R0C11 = keyIndex(0, 11);
constexpr byte R0C12 = keyIndex(0, 12);
constexpr byte R0C13 = keyIndex(0, 13);
constexpr byte R1C0 = keyIndex(1, 0);
constexpr byte R1C1 = keyIndex(1, 1);
constexpr byte R1C2 = keyIndex(1, 2);
constexpr byte R1C3 = keyIndex(1, 3);
constexpr byte R1C4 = keyIndex(1, 4);
constexpr byte R1C5 = keyIndex(1, 5);
constexpr byte R1C6 = keyIndex(1, 6);
constexpr byte R1C7 = keyIndex(1, 7);
constexpr byte R1C8 = keyIndex(1, 8);
constexpr byte R1C9 = keyIndex(1, 9);
constexpr byte R1C10 = keyIndex(1, 10);
constexpr byte R1C11 = keyIndex(1, 11);
constexpr byte R1C12 = keyIndex(1, 12);
constexpr byte R1C13 = keyIndex(1, 13);
constexpr byte R2C0 = keyIndex(2, 0);
constexpr byte R2C1 = keyIndex(2, 1);
constexpr byte R2C2 = keyIndex(2, 2);
constexpr byte R2C3 = keyIndex(2, 3);
constexpr byte R2C4 = keyIndex(2, 4);
constexpr byte R2C5 = keyIndex(2, 5);
constexpr byte R2C6 = keyIndex(2, 6);
constexpr byte R2C7 = keyIndex(2, 7);
constexpr byte R2C8 = keyIndex(2, 8);
constexpr byte R2C9 = keyIndex(2, 9);
constexpr byte R2C10 = keyIndex(2, 10);
constexpr byte R2C11 = keyIndex(2, 11);
constexpr byte R2C12 = keyIndex(2, 12);
constexpr byte R2C13 = keyIndex(2, 13);
constexpr byte R3C0 = keyIndex(3, 0);
constexpr byte R3C1 = keyIndex(3, 1);
constexpr byte R3C2 = keyIndex(3, 2);
constexpr byte R3C3 = keyIndex(3, 3);
constexpr byte R3C4 = keyIndex(3, 4);
constexpr byte R3C5 = keyIndex(3, 5);
constexpr byte R3C6 = keyIndex(3, 6);
constexpr byte R3C7 = keyIndex(3, 7);
constexpr byte R3C8 = keyIndex(3, 8);
constexpr byte R3C9 = keyIndex(3, 9);
constexpr byte R3C10 = keyIndex(3, 10);
constexpr byte R3C11 = keyIndex(3, 11);
constexpr byte R3C12 = keyIndex(3, 12);
constexpr byte R3C13 = keyIndex(3, 13);
constexpr byte R4C0 = keyIndex(4, 0);
constexpr byte R4C1 = keyIndex(4, 1);
constexpr byte R4C2 = keyIndex(4, 2);
constexpr byte R4C3 = keyIndex(4, 3);
constexpr byte R4C4 = keyIndex(4, 4);
constexpr byte R4C5 = keyIndex(4, 5);
constexpr byte R4C6 = keyIndex(4, 6);
constexpr byte R4C7 = keyIndex(4, 7);
constexpr byte R4C8 = keyIndex(4, 8);
constexpr byte R4C9 = keyIndex(4, 9);
constexpr byte R4C10 = keyIndex(4, 10);
constexpr byte R4C11 = keyIndex(4, 11);
constexpr byte R4C12 = keyIndex(4, 12);
constexpr byte R4C13 = keyIndex(4, 13);
constexpr byte R5C0 = keyIndex(5, 0);
constexpr byte R5C1 = keyIndex(5, 1);
constexpr byte R5C2 = keyIndex(5, 2);
constexpr byte R5C3 = keyIndex(5, 3);
constexpr byte R5C4 = keyIndex(5, 4);
constexpr byte R5C5 = keyIndex(5, 5);
constexpr byte R5C6 = keyIndex(5, 6);
constexpr byte R5C7 = keyIndex(5, 7);
constexpr byte R5C8 = keyIndex(5, 8);
constexpr byte R5C9 = keyIndex(5, 9);
constexpr byte R5C10 = keyIndex(5, 10);
constexpr byte R5C11 = keyIndex(5, 11);
constexpr byte R5C12 = keyIndex(5, 12);
constexpr byte R5C13 = keyIndex(5, 13);
#include "kaleidoscope/hardware/key_indexes.h"
extern kaleidoscope::hardware::ErgoDox &ErgoDox;

@ -137,88 +137,7 @@ class Model01 {
}
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/* To be used by the hardware implementations, `keyIndex` tells us the index of
* a key, from which we can figure out the row and column as needed. The index
* starts at one, so that plugins that work with a list of key indexes can use
* zero as a sentinel. This is important, because when we initialize arrays with
* fewer elements than the declared array size, the remaining elements will be
* zero. We can use this to avoid having to explicitly add a sentinel in
* user-facing code.
*/
constexpr byte keyIndex(byte row, byte col) {
return row * kaleidoscope::hardware::Model01::matrix_columns + col + 1;
}
constexpr byte R0C0 = keyIndex(0, 0);
constexpr byte R0C1 = keyIndex(0, 1);
constexpr byte R0C2 = keyIndex(0, 2);
constexpr byte R0C3 = keyIndex(0, 3);
constexpr byte R0C4 = keyIndex(0, 4);
constexpr byte R0C5 = keyIndex(0, 5);
constexpr byte R0C6 = keyIndex(0, 6);
constexpr byte R0C7 = keyIndex(0, 7);
constexpr byte R1C0 = keyIndex(1, 0);
constexpr byte R1C1 = keyIndex(1, 1);
constexpr byte R1C2 = keyIndex(1, 2);
constexpr byte R1C3 = keyIndex(1, 3);
constexpr byte R1C4 = keyIndex(1, 4);
constexpr byte R1C5 = keyIndex(1, 5);
constexpr byte R1C6 = keyIndex(1, 6);
constexpr byte R1C7 = keyIndex(1, 7);
constexpr byte R2C0 = keyIndex(2, 0);
constexpr byte R2C1 = keyIndex(2, 1);
constexpr byte R2C2 = keyIndex(2, 2);
constexpr byte R2C3 = keyIndex(2, 3);
constexpr byte R2C4 = keyIndex(2, 4);
constexpr byte R2C5 = keyIndex(2, 5);
constexpr byte R2C6 = keyIndex(2, 6);
constexpr byte R2C7 = keyIndex(2, 7);
constexpr byte R3C0 = keyIndex(3, 0);
constexpr byte R3C1 = keyIndex(3, 1);
constexpr byte R3C2 = keyIndex(3, 2);
constexpr byte R3C3 = keyIndex(3, 3);
constexpr byte R3C4 = keyIndex(3, 4);
constexpr byte R3C5 = keyIndex(3, 5);
constexpr byte R3C6 = keyIndex(3, 6);
constexpr byte R3C7 = keyIndex(3, 7);
constexpr byte R0C8 = keyIndex(0, 8);
constexpr byte R0C9 = keyIndex(0, 9);
constexpr byte R0C10 = keyIndex(0, 10);
constexpr byte R0C11 = keyIndex(0, 11);
constexpr byte R0C12 = keyIndex(0, 12);
constexpr byte R0C13 = keyIndex(0, 13);
constexpr byte R0C14 = keyIndex(0, 15);
constexpr byte R0C15 = keyIndex(0, 16);
constexpr byte R1C8 = keyIndex(1, 8);
constexpr byte R1C9 = keyIndex(1, 9);
constexpr byte R1C10 = keyIndex(1, 10);
constexpr byte R1C11 = keyIndex(1, 11);
constexpr byte R1C12 = keyIndex(1, 12);
constexpr byte R1C13 = keyIndex(1, 13);
constexpr byte R1C14 = keyIndex(1, 14);
constexpr byte R1C15 = keyIndex(1, 15);
constexpr byte R2C8 = keyIndex(2, 8);
constexpr byte R2C9 = keyIndex(2, 9);
constexpr byte R2C10 = keyIndex(2, 10);
constexpr byte R2C11 = keyIndex(2, 11);
constexpr byte R2C12 = keyIndex(2, 12);
constexpr byte R2C13 = keyIndex(2, 13);
constexpr byte R2C14 = keyIndex(2, 14);
constexpr byte R2C15 = keyIndex(2, 15);
constexpr byte R3C8 = keyIndex(3, 8);
constexpr byte R3C9 = keyIndex(3, 9);
constexpr byte R3C10 = keyIndex(3, 10);
constexpr byte R3C11 = keyIndex(3, 11);
constexpr byte R3C12 = keyIndex(3, 12);
constexpr byte R3C13 = keyIndex(3, 13);
constexpr byte R3C14 = keyIndex(3, 14);
constexpr byte R3C15 = keyIndex(3, 15);
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
#include "kaleidoscope/hardware/key_indexes.h"
#define KEYMAP_STACKED( \
r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, \

@ -0,0 +1,933 @@
/* -*- mode: c++ -*-
* Kaleidoscope - Firmware for computer input devices
* Copyright (C) 2018 Keyboard.io, Inc
*
* 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, version 3.
*
* 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
/* To be used by the hardware implementations, `keyIndex` tells us the index of
* a key, from which we can figure out the row and column as needed. The index
* starts at one, so that plugins that work with a list of key indexes can use
* zero as a sentinel. This is important, because when we initialize arrays with
* fewer elements than the declared array size, the remaining elements will be
* zero. We can use this to avoid having to explicitly add a sentinel in
* user-facing code.
*
* We're using a macro instead of a constexpr so that it is evaluated lazily,
* when `HARDWARE_IMPLEMENTATION` can be properly resolved.
*/
#define keyIndex(row,col) \
(uint8_t)((row * HARDWARE_IMPLEMENTATION::matrix_columns) + col + 1)
constexpr uint8_t R0C0 = keyIndex(0, 0);
constexpr uint8_t R0C1 = keyIndex(0, 1);
constexpr uint8_t R0C2 = keyIndex(0, 2);
constexpr uint8_t R0C3 = keyIndex(0, 3);
constexpr uint8_t R0C4 = keyIndex(0, 4);
constexpr uint8_t R0C5 = keyIndex(0, 5);
constexpr uint8_t R0C6 = keyIndex(0, 6);
constexpr uint8_t R0C7 = keyIndex(0, 7);
constexpr uint8_t R0C8 = keyIndex(0, 8);
constexpr uint8_t R0C9 = keyIndex(0, 9);
constexpr uint8_t R0C10 = keyIndex(0, 10);
constexpr uint8_t R0C11 = keyIndex(0, 11);
constexpr uint8_t R0C12 = keyIndex(0, 12);
constexpr uint8_t R0C13 = keyIndex(0, 13);
constexpr uint8_t R0C14 = keyIndex(0, 14);
constexpr uint8_t R0C15 = keyIndex(0, 15);
constexpr uint8_t R0C16 = keyIndex(0, 16);
constexpr uint8_t R0C17 = keyIndex(0, 17);
constexpr uint8_t R0C18 = keyIndex(0, 18);
constexpr uint8_t R0C19 = keyIndex(0, 19);
constexpr uint8_t R0C20 = keyIndex(0, 20);
constexpr uint8_t R0C21 = keyIndex(0, 21);
constexpr uint8_t R0C22 = keyIndex(0, 22);
constexpr uint8_t R0C23 = keyIndex(0, 23);
constexpr uint8_t R0C24 = keyIndex(0, 24);
constexpr uint8_t R0C25 = keyIndex(0, 25);
constexpr uint8_t R0C26 = keyIndex(0, 26);
constexpr uint8_t R0C27 = keyIndex(0, 27);
constexpr uint8_t R0C28 = keyIndex(0, 28);
constexpr uint8_t R0C29 = keyIndex(0, 29);
constexpr uint8_t R1C0 = keyIndex(1, 0);
constexpr uint8_t R1C1 = keyIndex(1, 1);
constexpr uint8_t R1C2 = keyIndex(1, 2);
constexpr uint8_t R1C3 = keyIndex(1, 3);
constexpr uint8_t R1C4 = keyIndex(1, 4);
constexpr uint8_t R1C5 = keyIndex(1, 5);
constexpr uint8_t R1C6 = keyIndex(1, 6);
constexpr uint8_t R1C7 = keyIndex(1, 7);
constexpr uint8_t R1C8 = keyIndex(1, 8);
constexpr uint8_t R1C9 = keyIndex(1, 9);
constexpr uint8_t R1C10 = keyIndex(1, 10);
constexpr uint8_t R1C11 = keyIndex(1, 11);
constexpr uint8_t R1C12 = keyIndex(1, 12);
constexpr uint8_t R1C13 = keyIndex(1, 13);
constexpr uint8_t R1C14 = keyIndex(1, 14);
constexpr uint8_t R1C15 = keyIndex(1, 15);
constexpr uint8_t R1C16 = keyIndex(1, 16);
constexpr uint8_t R1C17 = keyIndex(1, 17);
constexpr uint8_t R1C18 = keyIndex(1, 18);
constexpr uint8_t R1C19 = keyIndex(1, 19);
constexpr uint8_t R1C20 = keyIndex(1, 20);
constexpr uint8_t R1C21 = keyIndex(1, 21);
constexpr uint8_t R1C22 = keyIndex(1, 22);
constexpr uint8_t R1C23 = keyIndex(1, 23);
constexpr uint8_t R1C24 = keyIndex(1, 24);
constexpr uint8_t R1C25 = keyIndex(1, 25);
constexpr uint8_t R1C26 = keyIndex(1, 26);
constexpr uint8_t R1C27 = keyIndex(1, 27);
constexpr uint8_t R1C28 = keyIndex(1, 28);
constexpr uint8_t R1C29 = keyIndex(1, 29);
constexpr uint8_t R2C0 = keyIndex(2, 0);
constexpr uint8_t R2C1 = keyIndex(2, 1);
constexpr uint8_t R2C2 = keyIndex(2, 2);
constexpr uint8_t R2C3 = keyIndex(2, 3);
constexpr uint8_t R2C4 = keyIndex(2, 4);
constexpr uint8_t R2C5 = keyIndex(2, 5);
constexpr uint8_t R2C6 = keyIndex(2, 6);
constexpr uint8_t R2C7 = keyIndex(2, 7);
constexpr uint8_t R2C8 = keyIndex(2, 8);
constexpr uint8_t R2C9 = keyIndex(2, 9);
constexpr uint8_t R2C10 = keyIndex(2, 10);
constexpr uint8_t R2C11 = keyIndex(2, 11);
constexpr uint8_t R2C12 = keyIndex(2, 12);
constexpr uint8_t R2C13 = keyIndex(2, 13);
constexpr uint8_t R2C14 = keyIndex(2, 14);
constexpr uint8_t R2C15 = keyIndex(2, 15);
constexpr uint8_t R2C16 = keyIndex(2, 16);
constexpr uint8_t R2C17 = keyIndex(2, 17);
constexpr uint8_t R2C18 = keyIndex(2, 18);
constexpr uint8_t R2C19 = keyIndex(2, 19);
constexpr uint8_t R2C20 = keyIndex(2, 20);
constexpr uint8_t R2C21 = keyIndex(2, 21);
constexpr uint8_t R2C22 = keyIndex(2, 22);
constexpr uint8_t R2C23 = keyIndex(2, 23);
constexpr uint8_t R2C24 = keyIndex(2, 24);
constexpr uint8_t R2C25 = keyIndex(2, 25);
constexpr uint8_t R2C26 = keyIndex(2, 26);
constexpr uint8_t R2C27 = keyIndex(2, 27);
constexpr uint8_t R2C28 = keyIndex(2, 28);
constexpr uint8_t R2C29 = keyIndex(2, 29);
constexpr uint8_t R3C0 = keyIndex(3, 0);
constexpr uint8_t R3C1 = keyIndex(3, 1);
constexpr uint8_t R3C2 = keyIndex(3, 2);
constexpr uint8_t R3C3 = keyIndex(3, 3);
constexpr uint8_t R3C4 = keyIndex(3, 4);
constexpr uint8_t R3C5 = keyIndex(3, 5);
constexpr uint8_t R3C6 = keyIndex(3, 6);
constexpr uint8_t R3C7 = keyIndex(3, 7);
constexpr uint8_t R3C8 = keyIndex(3, 8);
constexpr uint8_t R3C9 = keyIndex(3, 9);
constexpr uint8_t R3C10 = keyIndex(3, 10);
constexpr uint8_t R3C11 = keyIndex(3, 11);
constexpr uint8_t R3C12 = keyIndex(3, 12);
constexpr uint8_t R3C13 = keyIndex(3, 13);
constexpr uint8_t R3C14 = keyIndex(3, 14);
constexpr uint8_t R3C15 = keyIndex(3, 15);
constexpr uint8_t R3C16 = keyIndex(3, 16);
constexpr uint8_t R3C17 = keyIndex(3, 17);
constexpr uint8_t R3C18 = keyIndex(3, 18);
constexpr uint8_t R3C19 = keyIndex(3, 19);
constexpr uint8_t R3C20 = keyIndex(3, 20);
constexpr uint8_t R3C21 = keyIndex(3, 21);
constexpr uint8_t R3C22 = keyIndex(3, 22);
constexpr uint8_t R3C23 = keyIndex(3, 23);
constexpr uint8_t R3C24 = keyIndex(3, 24);
constexpr uint8_t R3C25 = keyIndex(3, 25);
constexpr uint8_t R3C26 = keyIndex(3, 26);
constexpr uint8_t R3C27 = keyIndex(3, 27);
constexpr uint8_t R3C28 = keyIndex(3, 28);
constexpr uint8_t R3C29 = keyIndex(3, 29);
constexpr uint8_t R4C0 = keyIndex(4, 0);
constexpr uint8_t R4C1 = keyIndex(4, 1);
constexpr uint8_t R4C2 = keyIndex(4, 2);
constexpr uint8_t R4C3 = keyIndex(4, 3);
constexpr uint8_t R4C4 = keyIndex(4, 4);
constexpr uint8_t R4C5 = keyIndex(4, 5);
constexpr uint8_t R4C6 = keyIndex(4, 6);
constexpr uint8_t R4C7 = keyIndex(4, 7);
constexpr uint8_t R4C8 = keyIndex(4, 8);
constexpr uint8_t R4C9 = keyIndex(4, 9);
constexpr uint8_t R4C10 = keyIndex(4, 10);
constexpr uint8_t R4C11 = keyIndex(4, 11);
constexpr uint8_t R4C12 = keyIndex(4, 12);
constexpr uint8_t R4C13 = keyIndex(4, 13);
constexpr uint8_t R4C14 = keyIndex(4, 14);
constexpr uint8_t R4C15 = keyIndex(4, 15);
constexpr uint8_t R4C16 = keyIndex(4, 16);
constexpr uint8_t R4C17 = keyIndex(4, 17);
constexpr uint8_t R4C18 = keyIndex(4, 18);
constexpr uint8_t R4C19 = keyIndex(4, 19);
constexpr uint8_t R4C20 = keyIndex(4, 20);
constexpr uint8_t R4C21 = keyIndex(4, 21);
constexpr uint8_t R4C22 = keyIndex(4, 22);
constexpr uint8_t R4C23 = keyIndex(4, 23);
constexpr uint8_t R4C24 = keyIndex(4, 24);
constexpr uint8_t R4C25 = keyIndex(4, 25);
constexpr uint8_t R4C26 = keyIndex(4, 26);
constexpr uint8_t R4C27 = keyIndex(4, 27);
constexpr uint8_t R4C28 = keyIndex(4, 28);
constexpr uint8_t R4C29 = keyIndex(4, 29);
constexpr uint8_t R5C0 = keyIndex(5, 0);
constexpr uint8_t R5C1 = keyIndex(5, 1);
constexpr uint8_t R5C2 = keyIndex(5, 2);
constexpr uint8_t R5C3 = keyIndex(5, 3);
constexpr uint8_t R5C4 = keyIndex(5, 4);
constexpr uint8_t R5C5 = keyIndex(5, 5);
constexpr uint8_t R5C6 = keyIndex(5, 6);
constexpr uint8_t R5C7 = keyIndex(5, 7);
constexpr uint8_t R5C8 = keyIndex(5, 8);
constexpr uint8_t R5C9 = keyIndex(5, 9);
constexpr uint8_t R5C10 = keyIndex(5, 10);
constexpr uint8_t R5C11 = keyIndex(5, 11);
constexpr uint8_t R5C12 = keyIndex(5, 12);
constexpr uint8_t R5C13 = keyIndex(5, 13);
constexpr uint8_t R5C14 = keyIndex(5, 14);
constexpr uint8_t R5C15 = keyIndex(5, 15);
constexpr uint8_t R5C16 = keyIndex(5, 16);
constexpr uint8_t R5C17 = keyIndex(5, 17);
constexpr uint8_t R5C18 = keyIndex(5, 18);
constexpr uint8_t R5C19 = keyIndex(5, 19);
constexpr uint8_t R5C20 = keyIndex(5, 20);
constexpr uint8_t R5C21 = keyIndex(5, 21);
constexpr uint8_t R5C22 = keyIndex(5, 22);
constexpr uint8_t R5C23 = keyIndex(5, 23);
constexpr uint8_t R5C24 = keyIndex(5, 24);
constexpr uint8_t R5C25 = keyIndex(5, 25);
constexpr uint8_t R5C26 = keyIndex(5, 26);
constexpr uint8_t R5C27 = keyIndex(5, 27);
constexpr uint8_t R5C28 = keyIndex(5, 28);
constexpr uint8_t R5C29 = keyIndex(5, 29);
constexpr uint8_t R6C0 = keyIndex(6, 0);
constexpr uint8_t R6C1 = keyIndex(6, 1);
constexpr uint8_t R6C2 = keyIndex(6, 2);
constexpr uint8_t R6C3 = keyIndex(6, 3);
constexpr uint8_t R6C4 = keyIndex(6, 4);
constexpr uint8_t R6C5 = keyIndex(6, 5);
constexpr uint8_t R6C6 = keyIndex(6, 6);
constexpr uint8_t R6C7 = keyIndex(6, 7);
constexpr uint8_t R6C8 = keyIndex(6, 8);
constexpr uint8_t R6C9 = keyIndex(6, 9);
constexpr uint8_t R6C10 = keyIndex(6, 10);
constexpr uint8_t R6C11 = keyIndex(6, 11);
constexpr uint8_t R6C12 = keyIndex(6, 12);
constexpr uint8_t R6C13 = keyIndex(6, 13);
constexpr uint8_t R6C14 = keyIndex(6, 14);
constexpr uint8_t R6C15 = keyIndex(6, 15);
constexpr uint8_t R6C16 = keyIndex(6, 16);
constexpr uint8_t R6C17 = keyIndex(6, 17);
constexpr uint8_t R6C18 = keyIndex(6, 18);
constexpr uint8_t R6C19 = keyIndex(6, 19);
constexpr uint8_t R6C20 = keyIndex(6, 20);
constexpr uint8_t R6C21 = keyIndex(6, 21);
constexpr uint8_t R6C22 = keyIndex(6, 22);
constexpr uint8_t R6C23 = keyIndex(6, 23);
constexpr uint8_t R6C24 = keyIndex(6, 24);
constexpr uint8_t R6C25 = keyIndex(6, 25);
constexpr uint8_t R6C26 = keyIndex(6, 26);
constexpr uint8_t R6C27 = keyIndex(6, 27);
constexpr uint8_t R6C28 = keyIndex(6, 28);
constexpr uint8_t R6C29 = keyIndex(6, 29);
constexpr uint8_t R7C0 = keyIndex(7, 0);
constexpr uint8_t R7C1 = keyIndex(7, 1);
constexpr uint8_t R7C2 = keyIndex(7, 2);
constexpr uint8_t R7C3 = keyIndex(7, 3);
constexpr uint8_t R7C4 = keyIndex(7, 4);
constexpr uint8_t R7C5 = keyIndex(7, 5);
constexpr uint8_t R7C6 = keyIndex(7, 6);
constexpr uint8_t R7C7 = keyIndex(7, 7);
constexpr uint8_t R7C8 = keyIndex(7, 8);
constexpr uint8_t R7C9 = keyIndex(7, 9);
constexpr uint8_t R7C10 = keyIndex(7, 10);
constexpr uint8_t R7C11 = keyIndex(7, 11);
constexpr uint8_t R7C12 = keyIndex(7, 12);
constexpr uint8_t R7C13 = keyIndex(7, 13);
constexpr uint8_t R7C14 = keyIndex(7, 14);
constexpr uint8_t R7C15 = keyIndex(7, 15);
constexpr uint8_t R7C16 = keyIndex(7, 16);
constexpr uint8_t R7C17 = keyIndex(7, 17);
constexpr uint8_t R7C18 = keyIndex(7, 18);
constexpr uint8_t R7C19 = keyIndex(7, 19);
constexpr uint8_t R7C20 = keyIndex(7, 20);
constexpr uint8_t R7C21 = keyIndex(7, 21);
constexpr uint8_t R7C22 = keyIndex(7, 22);
constexpr uint8_t R7C23 = keyIndex(7, 23);
constexpr uint8_t R7C24 = keyIndex(7, 24);
constexpr uint8_t R7C25 = keyIndex(7, 25);
constexpr uint8_t R7C26 = keyIndex(7, 26);
constexpr uint8_t R7C27 = keyIndex(7, 27);
constexpr uint8_t R7C28 = keyIndex(7, 28);
constexpr uint8_t R7C29 = keyIndex(7, 29);
constexpr uint8_t R8C0 = keyIndex(8, 0);
constexpr uint8_t R8C1 = keyIndex(8, 1);
constexpr uint8_t R8C2 = keyIndex(8, 2);
constexpr uint8_t R8C3 = keyIndex(8, 3);
constexpr uint8_t R8C4 = keyIndex(8, 4);
constexpr uint8_t R8C5 = keyIndex(8, 5);
constexpr uint8_t R8C6 = keyIndex(8, 6);
constexpr uint8_t R8C7 = keyIndex(8, 7);
constexpr uint8_t R8C8 = keyIndex(8, 8);
constexpr uint8_t R8C9 = keyIndex(8, 9);
constexpr uint8_t R8C10 = keyIndex(8, 10);
constexpr uint8_t R8C11 = keyIndex(8, 11);
constexpr uint8_t R8C12 = keyIndex(8, 12);
constexpr uint8_t R8C13 = keyIndex(8, 13);
constexpr uint8_t R8C14 = keyIndex(8, 14);
constexpr uint8_t R8C15 = keyIndex(8, 15);
constexpr uint8_t R8C16 = keyIndex(8, 16);
constexpr uint8_t R8C17 = keyIndex(8, 17);
constexpr uint8_t R8C18 = keyIndex(8, 18);
constexpr uint8_t R8C19 = keyIndex(8, 19);
constexpr uint8_t R8C20 = keyIndex(8, 20);
constexpr uint8_t R8C21 = keyIndex(8, 21);
constexpr uint8_t R8C22 = keyIndex(8, 22);
constexpr uint8_t R8C23 = keyIndex(8, 23);
constexpr uint8_t R8C24 = keyIndex(8, 24);
constexpr uint8_t R8C25 = keyIndex(8, 25);
constexpr uint8_t R8C26 = keyIndex(8, 26);
constexpr uint8_t R8C27 = keyIndex(8, 27);
constexpr uint8_t R8C28 = keyIndex(8, 28);
constexpr uint8_t R8C29 = keyIndex(8, 29);
constexpr uint8_t R9C0 = keyIndex(9, 0);
constexpr uint8_t R9C1 = keyIndex(9, 1);
constexpr uint8_t R9C2 = keyIndex(9, 2);
constexpr uint8_t R9C3 = keyIndex(9, 3);
constexpr uint8_t R9C4 = keyIndex(9, 4);
constexpr uint8_t R9C5 = keyIndex(9, 5);
constexpr uint8_t R9C6 = keyIndex(9, 6);
constexpr uint8_t R9C7 = keyIndex(9, 7);
constexpr uint8_t R9C8 = keyIndex(9, 8);
constexpr uint8_t R9C9 = keyIndex(9, 9);
constexpr uint8_t R9C10 = keyIndex(9, 10);
constexpr uint8_t R9C11 = keyIndex(9, 11);
constexpr uint8_t R9C12 = keyIndex(9, 12);
constexpr uint8_t R9C13 = keyIndex(9, 13);
constexpr uint8_t R9C14 = keyIndex(9, 14);
constexpr uint8_t R9C15 = keyIndex(9, 15);
constexpr uint8_t R9C16 = keyIndex(9, 16);
constexpr uint8_t R9C17 = keyIndex(9, 17);
constexpr uint8_t R9C18 = keyIndex(9, 18);
constexpr uint8_t R9C19 = keyIndex(9, 19);
constexpr uint8_t R9C20 = keyIndex(9, 20);
constexpr uint8_t R9C21 = keyIndex(9, 21);
constexpr uint8_t R9C22 = keyIndex(9, 22);
constexpr uint8_t R9C23 = keyIndex(9, 23);
constexpr uint8_t R9C24 = keyIndex(9, 24);
constexpr uint8_t R9C25 = keyIndex(9, 25);
constexpr uint8_t R9C26 = keyIndex(9, 26);
constexpr uint8_t R9C27 = keyIndex(9, 27);
constexpr uint8_t R9C28 = keyIndex(9, 28);
constexpr uint8_t R9C29 = keyIndex(9, 29);
constexpr uint8_t R10C0 = keyIndex(10, 0);
constexpr uint8_t R10C1 = keyIndex(10, 1);
constexpr uint8_t R10C2 = keyIndex(10, 2);
constexpr uint8_t R10C3 = keyIndex(10, 3);
constexpr uint8_t R10C4 = keyIndex(10, 4);
constexpr uint8_t R10C5 = keyIndex(10, 5);
constexpr uint8_t R10C6 = keyIndex(10, 6);
constexpr uint8_t R10C7 = keyIndex(10, 7);
constexpr uint8_t R10C8 = keyIndex(10, 8);
constexpr uint8_t R10C9 = keyIndex(10, 9);
constexpr uint8_t R10C10 = keyIndex(10, 10);
constexpr uint8_t R10C11 = keyIndex(10, 11);
constexpr uint8_t R10C12 = keyIndex(10, 12);
constexpr uint8_t R10C13 = keyIndex(10, 13);
constexpr uint8_t R10C14 = keyIndex(10, 14);
constexpr uint8_t R10C15 = keyIndex(10, 15);
constexpr uint8_t R10C16 = keyIndex(10, 16);
constexpr uint8_t R10C17 = keyIndex(10, 17);
constexpr uint8_t R10C18 = keyIndex(10, 18);
constexpr uint8_t R10C19 = keyIndex(10, 19);
constexpr uint8_t R10C20 = keyIndex(10, 20);
constexpr uint8_t R10C21 = keyIndex(10, 21);
constexpr uint8_t R10C22 = keyIndex(10, 22);
constexpr uint8_t R10C23 = keyIndex(10, 23);
constexpr uint8_t R10C24 = keyIndex(10, 24);
constexpr uint8_t R10C25 = keyIndex(10, 25);
constexpr uint8_t R10C26 = keyIndex(10, 26);
constexpr uint8_t R10C27 = keyIndex(10, 27);
constexpr uint8_t R10C28 = keyIndex(10, 28);
constexpr uint8_t R10C29 = keyIndex(10, 29);
constexpr uint8_t R11C0 = keyIndex(11, 0);
constexpr uint8_t R11C1 = keyIndex(11, 1);
constexpr uint8_t R11C2 = keyIndex(11, 2);
constexpr uint8_t R11C3 = keyIndex(11, 3);
constexpr uint8_t R11C4 = keyIndex(11, 4);
constexpr uint8_t R11C5 = keyIndex(11, 5);
constexpr uint8_t R11C6 = keyIndex(11, 6);
constexpr uint8_t R11C7 = keyIndex(11, 7);
constexpr uint8_t R11C8 = keyIndex(11, 8);
constexpr uint8_t R11C9 = keyIndex(11, 9);
constexpr uint8_t R11C10 = keyIndex(11, 10);
constexpr uint8_t R11C11 = keyIndex(11, 11);
constexpr uint8_t R11C12 = keyIndex(11, 12);
constexpr uint8_t R11C13 = keyIndex(11, 13);
constexpr uint8_t R11C14 = keyIndex(11, 14);
constexpr uint8_t R11C15 = keyIndex(11, 15);
constexpr uint8_t R11C16 = keyIndex(11, 16);
constexpr uint8_t R11C17 = keyIndex(11, 17);
constexpr uint8_t R11C18 = keyIndex(11, 18);
constexpr uint8_t R11C19 = keyIndex(11, 19);
constexpr uint8_t R11C20 = keyIndex(11, 20);
constexpr uint8_t R11C21 = keyIndex(11, 21);
constexpr uint8_t R11C22 = keyIndex(11, 22);
constexpr uint8_t R11C23 = keyIndex(11, 23);
constexpr uint8_t R11C24 = keyIndex(11, 24);
constexpr uint8_t R11C25 = keyIndex(11, 25);
constexpr uint8_t R11C26 = keyIndex(11, 26);
constexpr uint8_t R11C27 = keyIndex(11, 27);
constexpr uint8_t R11C28 = keyIndex(11, 28);
constexpr uint8_t R11C29 = keyIndex(11, 29);
constexpr uint8_t R12C0 = keyIndex(12, 0);
constexpr uint8_t R12C1 = keyIndex(12, 1);
constexpr uint8_t R12C2 = keyIndex(12, 2);
constexpr uint8_t R12C3 = keyIndex(12, 3);
constexpr uint8_t R12C4 = keyIndex(12, 4);
constexpr uint8_t R12C5 = keyIndex(12, 5);
constexpr uint8_t R12C6 = keyIndex(12, 6);
constexpr uint8_t R12C7 = keyIndex(12, 7);
constexpr uint8_t R12C8 = keyIndex(12, 8);
constexpr uint8_t R12C9 = keyIndex(12, 9);
constexpr uint8_t R12C10 = keyIndex(12, 10);
constexpr uint8_t R12C11 = keyIndex(12, 11);
constexpr uint8_t R12C12 = keyIndex(12, 12);
constexpr uint8_t R12C13 = keyIndex(12, 13);
constexpr uint8_t R12C14 = keyIndex(12, 14);
constexpr uint8_t R12C15 = keyIndex(12, 15);
constexpr uint8_t R12C16 = keyIndex(12, 16);
constexpr uint8_t R12C17 = keyIndex(12, 17);
constexpr uint8_t R12C18 = keyIndex(12, 18);
constexpr uint8_t R12C19 = keyIndex(12, 19);
constexpr uint8_t R12C20 = keyIndex(12, 20);
constexpr uint8_t R12C21 = keyIndex(12, 21);
constexpr uint8_t R12C22 = keyIndex(12, 22);
constexpr uint8_t R12C23 = keyIndex(12, 23);
constexpr uint8_t R12C24 = keyIndex(12, 24);
constexpr uint8_t R12C25 = keyIndex(12, 25);
constexpr uint8_t R12C26 = keyIndex(12, 26);
constexpr uint8_t R12C27 = keyIndex(12, 27);
constexpr uint8_t R12C28 = keyIndex(12, 28);
constexpr uint8_t R12C29 = keyIndex(12, 29);
constexpr uint8_t R13C0 = keyIndex(13, 0);
constexpr uint8_t R13C1 = keyIndex(13, 1);
constexpr uint8_t R13C2 = keyIndex(13, 2);
constexpr uint8_t R13C3 = keyIndex(13, 3);
constexpr uint8_t R13C4 = keyIndex(13, 4);
constexpr uint8_t R13C5 = keyIndex(13, 5);
constexpr uint8_t R13C6 = keyIndex(13, 6);
constexpr uint8_t R13C7 = keyIndex(13, 7);
constexpr uint8_t R13C8 = keyIndex(13, 8);
constexpr uint8_t R13C9 = keyIndex(13, 9);
constexpr uint8_t R13C10 = keyIndex(13, 10);
constexpr uint8_t R13C11 = keyIndex(13, 11);
constexpr uint8_t R13C12 = keyIndex(13, 12);
constexpr uint8_t R13C13 = keyIndex(13, 13);
constexpr uint8_t R13C14 = keyIndex(13, 14);
constexpr uint8_t R13C15 = keyIndex(13, 15);
constexpr uint8_t R13C16 = keyIndex(13, 16);
constexpr uint8_t R13C17 = keyIndex(13, 17);
constexpr uint8_t R13C18 = keyIndex(13, 18);
constexpr uint8_t R13C19 = keyIndex(13, 19);
constexpr uint8_t R13C20 = keyIndex(13, 20);
constexpr uint8_t R13C21 = keyIndex(13, 21);
constexpr uint8_t R13C22 = keyIndex(13, 22);
constexpr uint8_t R13C23 = keyIndex(13, 23);
constexpr uint8_t R13C24 = keyIndex(13, 24);
constexpr uint8_t R13C25 = keyIndex(13, 25);
constexpr uint8_t R13C26 = keyIndex(13, 26);
constexpr uint8_t R13C27 = keyIndex(13, 27);
constexpr uint8_t R13C28 = keyIndex(13, 28);
constexpr uint8_t R13C29 = keyIndex(13, 29);
constexpr uint8_t R14C0 = keyIndex(14, 0);
constexpr uint8_t R14C1 = keyIndex(14, 1);
constexpr uint8_t R14C2 = keyIndex(14, 2);
constexpr uint8_t R14C3 = keyIndex(14, 3);
constexpr uint8_t R14C4 = keyIndex(14, 4);
constexpr uint8_t R14C5 = keyIndex(14, 5);
constexpr uint8_t R14C6 = keyIndex(14, 6);
constexpr uint8_t R14C7 = keyIndex(14, 7);
constexpr uint8_t R14C8 = keyIndex(14, 8);
constexpr uint8_t R14C9 = keyIndex(14, 9);
constexpr uint8_t R14C10 = keyIndex(14, 10);
constexpr uint8_t R14C11 = keyIndex(14, 11);
constexpr uint8_t R14C12 = keyIndex(14, 12);
constexpr uint8_t R14C13 = keyIndex(14, 13);
constexpr uint8_t R14C14 = keyIndex(14, 14);
constexpr uint8_t R14C15 = keyIndex(14, 15);
constexpr uint8_t R14C16 = keyIndex(14, 16);
constexpr uint8_t R14C17 = keyIndex(14, 17);
constexpr uint8_t R14C18 = keyIndex(14, 18);
constexpr uint8_t R14C19 = keyIndex(14, 19);
constexpr uint8_t R14C20 = keyIndex(14, 20);
constexpr uint8_t R14C21 = keyIndex(14, 21);
constexpr uint8_t R14C22 = keyIndex(14, 22);
constexpr uint8_t R14C23 = keyIndex(14, 23);
constexpr uint8_t R14C24 = keyIndex(14, 24);
constexpr uint8_t R14C25 = keyIndex(14, 25);
constexpr uint8_t R14C26 = keyIndex(14, 26);
constexpr uint8_t R14C27 = keyIndex(14, 27);
constexpr uint8_t R14C28 = keyIndex(14, 28);
constexpr uint8_t R14C29 = keyIndex(14, 29);
constexpr uint8_t R15C0 = keyIndex(15, 0);
constexpr uint8_t R15C1 = keyIndex(15, 1);
constexpr uint8_t R15C2 = keyIndex(15, 2);
constexpr uint8_t R15C3 = keyIndex(15, 3);
constexpr uint8_t R15C4 = keyIndex(15, 4);
constexpr uint8_t R15C5 = keyIndex(15, 5);
constexpr uint8_t R15C6 = keyIndex(15, 6);
constexpr uint8_t R15C7 = keyIndex(15, 7);
constexpr uint8_t R15C8 = keyIndex(15, 8);
constexpr uint8_t R15C9 = keyIndex(15, 9);
constexpr uint8_t R15C10 = keyIndex(15, 10);
constexpr uint8_t R15C11 = keyIndex(15, 11);
constexpr uint8_t R15C12 = keyIndex(15, 12);
constexpr uint8_t R15C13 = keyIndex(15, 13);
constexpr uint8_t R15C14 = keyIndex(15, 14);
constexpr uint8_t R15C15 = keyIndex(15, 15);
constexpr uint8_t R15C16 = keyIndex(15, 16);
constexpr uint8_t R15C17 = keyIndex(15, 17);
constexpr uint8_t R15C18 = keyIndex(15, 18);
constexpr uint8_t R15C19 = keyIndex(15, 19);
constexpr uint8_t R15C20 = keyIndex(15, 20);
constexpr uint8_t R15C21 = keyIndex(15, 21);
constexpr uint8_t R15C22 = keyIndex(15, 22);
constexpr uint8_t R15C23 = keyIndex(15, 23);
constexpr uint8_t R15C24 = keyIndex(15, 24);
constexpr uint8_t R15C25 = keyIndex(15, 25);
constexpr uint8_t R15C26 = keyIndex(15, 26);
constexpr uint8_t R15C27 = keyIndex(15, 27);
constexpr uint8_t R15C28 = keyIndex(15, 28);
constexpr uint8_t R15C29 = keyIndex(15, 29);
constexpr uint8_t R16C0 = keyIndex(16, 0);
constexpr uint8_t R16C1 = keyIndex(16, 1);
constexpr uint8_t R16C2 = keyIndex(16, 2);
constexpr uint8_t R16C3 = keyIndex(16, 3);
constexpr uint8_t R16C4 = keyIndex(16, 4);
constexpr uint8_t R16C5 = keyIndex(16, 5);
constexpr uint8_t R16C6 = keyIndex(16, 6);
constexpr uint8_t R16C7 = keyIndex(16, 7);
constexpr uint8_t R16C8 = keyIndex(16, 8);
constexpr uint8_t R16C9 = keyIndex(16, 9);
constexpr uint8_t R16C10 = keyIndex(16, 10);
constexpr uint8_t R16C11 = keyIndex(16, 11);
constexpr uint8_t R16C12 = keyIndex(16, 12);
constexpr uint8_t R16C13 = keyIndex(16, 13);
constexpr uint8_t R16C14 = keyIndex(16, 14);
constexpr uint8_t R16C15 = keyIndex(16, 15);
constexpr uint8_t R16C16 = keyIndex(16, 16);
constexpr uint8_t R16C17 = keyIndex(16, 17);
constexpr uint8_t R16C18 = keyIndex(16, 18);
constexpr uint8_t R16C19 = keyIndex(16, 19);
constexpr uint8_t R16C20 = keyIndex(16, 20);
constexpr uint8_t R16C21 = keyIndex(16, 21);
constexpr uint8_t R16C22 = keyIndex(16, 22);
constexpr uint8_t R16C23 = keyIndex(16, 23);
constexpr uint8_t R16C24 = keyIndex(16, 24);
constexpr uint8_t R16C25 = keyIndex(16, 25);
constexpr uint8_t R16C26 = keyIndex(16, 26);
constexpr uint8_t R16C27 = keyIndex(16, 27);
constexpr uint8_t R16C28 = keyIndex(16, 28);
constexpr uint8_t R16C29 = keyIndex(16, 29);
constexpr uint8_t R17C0 = keyIndex(17, 0);
constexpr uint8_t R17C1 = keyIndex(17, 1);
constexpr uint8_t R17C2 = keyIndex(17, 2);
constexpr uint8_t R17C3 = keyIndex(17, 3);
constexpr uint8_t R17C4 = keyIndex(17, 4);
constexpr uint8_t R17C5 = keyIndex(17, 5);
constexpr uint8_t R17C6 = keyIndex(17, 6);
constexpr uint8_t R17C7 = keyIndex(17, 7);
constexpr uint8_t R17C8 = keyIndex(17, 8);
constexpr uint8_t R17C9 = keyIndex(17, 9);
constexpr uint8_t R17C10 = keyIndex(17, 10);
constexpr uint8_t R17C11 = keyIndex(17, 11);
constexpr uint8_t R17C12 = keyIndex(17, 12);
constexpr uint8_t R17C13 = keyIndex(17, 13);
constexpr uint8_t R17C14 = keyIndex(17, 14);
constexpr uint8_t R17C15 = keyIndex(17, 15);
constexpr uint8_t R17C16 = keyIndex(17, 16);
constexpr uint8_t R17C17 = keyIndex(17, 17);
constexpr uint8_t R17C18 = keyIndex(17, 18);
constexpr uint8_t R17C19 = keyIndex(17, 19);
constexpr uint8_t R17C20 = keyIndex(17, 20);
constexpr uint8_t R17C21 = keyIndex(17, 21);
constexpr uint8_t R17C22 = keyIndex(17, 22);
constexpr uint8_t R17C23 = keyIndex(17, 23);
constexpr uint8_t R17C24 = keyIndex(17, 24);
constexpr uint8_t R17C25 = keyIndex(17, 25);
constexpr uint8_t R17C26 = keyIndex(17, 26);
constexpr uint8_t R17C27 = keyIndex(17, 27);
constexpr uint8_t R17C28 = keyIndex(17, 28);
constexpr uint8_t R17C29 = keyIndex(17, 29);
constexpr uint8_t R18C0 = keyIndex(18, 0);
constexpr uint8_t R18C1 = keyIndex(18, 1);
constexpr uint8_t R18C2 = keyIndex(18, 2);
constexpr uint8_t R18C3 = keyIndex(18, 3);
constexpr uint8_t R18C4 = keyIndex(18, 4);
constexpr uint8_t R18C5 = keyIndex(18, 5);
constexpr uint8_t R18C6 = keyIndex(18, 6);
constexpr uint8_t R18C7 = keyIndex(18, 7);
constexpr uint8_t R18C8 = keyIndex(18, 8);
constexpr uint8_t R18C9 = keyIndex(18, 9);
constexpr uint8_t R18C10 = keyIndex(18, 10);
constexpr uint8_t R18C11 = keyIndex(18, 11);
constexpr uint8_t R18C12 = keyIndex(18, 12);
constexpr uint8_t R18C13 = keyIndex(18, 13);
constexpr uint8_t R18C14 = keyIndex(18, 14);
constexpr uint8_t R18C15 = keyIndex(18, 15);
constexpr uint8_t R18C16 = keyIndex(18, 16);
constexpr uint8_t R18C17 = keyIndex(18, 17);
constexpr uint8_t R18C18 = keyIndex(18, 18);
constexpr uint8_t R18C19 = keyIndex(18, 19);
constexpr uint8_t R18C20 = keyIndex(18, 20);
constexpr uint8_t R18C21 = keyIndex(18, 21);
constexpr uint8_t R18C22 = keyIndex(18, 22);
constexpr uint8_t R18C23 = keyIndex(18, 23);
constexpr uint8_t R18C24 = keyIndex(18, 24);
constexpr uint8_t R18C25 = keyIndex(18, 25);
constexpr uint8_t R18C26 = keyIndex(18, 26);
constexpr uint8_t R18C27 = keyIndex(18, 27);
constexpr uint8_t R18C28 = keyIndex(18, 28);
constexpr uint8_t R18C29 = keyIndex(18, 29);
constexpr uint8_t R19C0 = keyIndex(19, 0);
constexpr uint8_t R19C1 = keyIndex(19, 1);
constexpr uint8_t R19C2 = keyIndex(19, 2);
constexpr uint8_t R19C3 = keyIndex(19, 3);
constexpr uint8_t R19C4 = keyIndex(19, 4);
constexpr uint8_t R19C5 = keyIndex(19, 5);
constexpr uint8_t R19C6 = keyIndex(19, 6);
constexpr uint8_t R19C7 = keyIndex(19, 7);
constexpr uint8_t R19C8 = keyIndex(19, 8);
constexpr uint8_t R19C9 = keyIndex(19, 9);
constexpr uint8_t R19C10 = keyIndex(19, 10);
constexpr uint8_t R19C11 = keyIndex(19, 11);
constexpr uint8_t R19C12 = keyIndex(19, 12);
constexpr uint8_t R19C13 = keyIndex(19, 13);
constexpr uint8_t R19C14 = keyIndex(19, 14);
constexpr uint8_t R19C15 = keyIndex(19, 15);
constexpr uint8_t R19C16 = keyIndex(19, 16);
constexpr uint8_t R19C17 = keyIndex(19, 17);
constexpr uint8_t R19C18 = keyIndex(19, 18);
constexpr uint8_t R19C19 = keyIndex(19, 19);
constexpr uint8_t R19C20 = keyIndex(19, 20);
constexpr uint8_t R19C21 = keyIndex(19, 21);
constexpr uint8_t R19C22 = keyIndex(19, 22);
constexpr uint8_t R19C23 = keyIndex(19, 23);
constexpr uint8_t R19C24 = keyIndex(19, 24);
constexpr uint8_t R19C25 = keyIndex(19, 25);
constexpr uint8_t R19C26 = keyIndex(19, 26);
constexpr uint8_t R19C27 = keyIndex(19, 27);
constexpr uint8_t R19C28 = keyIndex(19, 28);
constexpr uint8_t R19C29 = keyIndex(19, 29);
constexpr uint8_t R20C0 = keyIndex(20, 0);
constexpr uint8_t R20C1 = keyIndex(20, 1);
constexpr uint8_t R20C2 = keyIndex(20, 2);
constexpr uint8_t R20C3 = keyIndex(20, 3);
constexpr uint8_t R20C4 = keyIndex(20, 4);
constexpr uint8_t R20C5 = keyIndex(20, 5);
constexpr uint8_t R20C6 = keyIndex(20, 6);
constexpr uint8_t R20C7 = keyIndex(20, 7);
constexpr uint8_t R20C8 = keyIndex(20, 8);
constexpr uint8_t R20C9 = keyIndex(20, 9);
constexpr uint8_t R20C10 = keyIndex(20, 10);
constexpr uint8_t R20C11 = keyIndex(20, 11);
constexpr uint8_t R20C12 = keyIndex(20, 12);
constexpr uint8_t R20C13 = keyIndex(20, 13);
constexpr uint8_t R20C14 = keyIndex(20, 14);
constexpr uint8_t R20C15 = keyIndex(20, 15);
constexpr uint8_t R20C16 = keyIndex(20, 16);
constexpr uint8_t R20C17 = keyIndex(20, 17);
constexpr uint8_t R20C18 = keyIndex(20, 18);
constexpr uint8_t R20C19 = keyIndex(20, 19);
constexpr uint8_t R20C20 = keyIndex(20, 20);
constexpr uint8_t R20C21 = keyIndex(20, 21);
constexpr uint8_t R20C22 = keyIndex(20, 22);
constexpr uint8_t R20C23 = keyIndex(20, 23);
constexpr uint8_t R20C24 = keyIndex(20, 24);
constexpr uint8_t R20C25 = keyIndex(20, 25);
constexpr uint8_t R20C26 = keyIndex(20, 26);
constexpr uint8_t R20C27 = keyIndex(20, 27);
constexpr uint8_t R20C28 = keyIndex(20, 28);
constexpr uint8_t R20C29 = keyIndex(20, 29);
constexpr uint8_t R21C0 = keyIndex(21, 0);
constexpr uint8_t R21C1 = keyIndex(21, 1);
constexpr uint8_t R21C2 = keyIndex(21, 2);
constexpr uint8_t R21C3 = keyIndex(21, 3);
constexpr uint8_t R21C4 = keyIndex(21, 4);
constexpr uint8_t R21C5 = keyIndex(21, 5);
constexpr uint8_t R21C6 = keyIndex(21, 6);
constexpr uint8_t R21C7 = keyIndex(21, 7);
constexpr uint8_t R21C8 = keyIndex(21, 8);
constexpr uint8_t R21C9 = keyIndex(21, 9);
constexpr uint8_t R21C10 = keyIndex(21, 10);
constexpr uint8_t R21C11 = keyIndex(21, 11);
constexpr uint8_t R21C12 = keyIndex(21, 12);
constexpr uint8_t R21C13 = keyIndex(21, 13);
constexpr uint8_t R21C14 = keyIndex(21, 14);
constexpr uint8_t R21C15 = keyIndex(21, 15);
constexpr uint8_t R21C16 = keyIndex(21, 16);
constexpr uint8_t R21C17 = keyIndex(21, 17);
constexpr uint8_t R21C18 = keyIndex(21, 18);
constexpr uint8_t R21C19 = keyIndex(21, 19);
constexpr uint8_t R21C20 = keyIndex(21, 20);
constexpr uint8_t R21C21 = keyIndex(21, 21);
constexpr uint8_t R21C22 = keyIndex(21, 22);
constexpr uint8_t R21C23 = keyIndex(21, 23);
constexpr uint8_t R21C24 = keyIndex(21, 24);
constexpr uint8_t R21C25 = keyIndex(21, 25);
constexpr uint8_t R21C26 = keyIndex(21, 26);
constexpr uint8_t R21C27 = keyIndex(21, 27);
constexpr uint8_t R21C28 = keyIndex(21, 28);
constexpr uint8_t R21C29 = keyIndex(21, 29);
constexpr uint8_t R22C0 = keyIndex(22, 0);
constexpr uint8_t R22C1 = keyIndex(22, 1);
constexpr uint8_t R22C2 = keyIndex(22, 2);
constexpr uint8_t R22C3 = keyIndex(22, 3);
constexpr uint8_t R22C4 = keyIndex(22, 4);
constexpr uint8_t R22C5 = keyIndex(22, 5);
constexpr uint8_t R22C6 = keyIndex(22, 6);
constexpr uint8_t R22C7 = keyIndex(22, 7);
constexpr uint8_t R22C8 = keyIndex(22, 8);
constexpr uint8_t R22C9 = keyIndex(22, 9);
constexpr uint8_t R22C10 = keyIndex(22, 10);
constexpr uint8_t R22C11 = keyIndex(22, 11);
constexpr uint8_t R22C12 = keyIndex(22, 12);
constexpr uint8_t R22C13 = keyIndex(22, 13);
constexpr uint8_t R22C14 = keyIndex(22, 14);
constexpr uint8_t R22C15 = keyIndex(22, 15);
constexpr uint8_t R22C16 = keyIndex(22, 16);
constexpr uint8_t R22C17 = keyIndex(22, 17);
constexpr uint8_t R22C18 = keyIndex(22, 18);
constexpr uint8_t R22C19 = keyIndex(22, 19);
constexpr uint8_t R22C20 = keyIndex(22, 20);
constexpr uint8_t R22C21 = keyIndex(22, 21);
constexpr uint8_t R22C22 = keyIndex(22, 22);
constexpr uint8_t R22C23 = keyIndex(22, 23);
constexpr uint8_t R22C24 = keyIndex(22, 24);
constexpr uint8_t R22C25 = keyIndex(22, 25);
constexpr uint8_t R22C26 = keyIndex(22, 26);
constexpr uint8_t R22C27 = keyIndex(22, 27);
constexpr uint8_t R22C28 = keyIndex(22, 28);
constexpr uint8_t R22C29 = keyIndex(22, 29);
constexpr uint8_t R23C0 = keyIndex(23, 0);
constexpr uint8_t R23C1 = keyIndex(23, 1);
constexpr uint8_t R23C2 = keyIndex(23, 2);
constexpr uint8_t R23C3 = keyIndex(23, 3);
constexpr uint8_t R23C4 = keyIndex(23, 4);
constexpr uint8_t R23C5 = keyIndex(23, 5);
constexpr uint8_t R23C6 = keyIndex(23, 6);
constexpr uint8_t R23C7 = keyIndex(23, 7);
constexpr uint8_t R23C8 = keyIndex(23, 8);
constexpr uint8_t R23C9 = keyIndex(23, 9);
constexpr uint8_t R23C10 = keyIndex(23, 10);
constexpr uint8_t R23C11 = keyIndex(23, 11);
constexpr uint8_t R23C12 = keyIndex(23, 12);
constexpr uint8_t R23C13 = keyIndex(23, 13);
constexpr uint8_t R23C14 = keyIndex(23, 14);
constexpr uint8_t R23C15 = keyIndex(23, 15);
constexpr uint8_t R23C16 = keyIndex(23, 16);
constexpr uint8_t R23C17 = keyIndex(23, 17);
constexpr uint8_t R23C18 = keyIndex(23, 18);
constexpr uint8_t R23C19 = keyIndex(23, 19);
constexpr uint8_t R23C20 = keyIndex(23, 20);
constexpr uint8_t R23C21 = keyIndex(23, 21);
constexpr uint8_t R23C22 = keyIndex(23, 22);
constexpr uint8_t R23C23 = keyIndex(23, 23);
constexpr uint8_t R23C24 = keyIndex(23, 24);
constexpr uint8_t R23C25 = keyIndex(23, 25);
constexpr uint8_t R23C26 = keyIndex(23, 26);
constexpr uint8_t R23C27 = keyIndex(23, 27);
constexpr uint8_t R23C28 = keyIndex(23, 28);
constexpr uint8_t R23C29 = keyIndex(23, 29);
constexpr uint8_t R24C0 = keyIndex(24, 0);
constexpr uint8_t R24C1 = keyIndex(24, 1);
constexpr uint8_t R24C2 = keyIndex(24, 2);
constexpr uint8_t R24C3 = keyIndex(24, 3);
constexpr uint8_t R24C4 = keyIndex(24, 4);
constexpr uint8_t R24C5 = keyIndex(24, 5);
constexpr uint8_t R24C6 = keyIndex(24, 6);
constexpr uint8_t R24C7 = keyIndex(24, 7);
constexpr uint8_t R24C8 = keyIndex(24, 8);
constexpr uint8_t R24C9 = keyIndex(24, 9);
constexpr uint8_t R24C10 = keyIndex(24, 10);
constexpr uint8_t R24C11 = keyIndex(24, 11);
constexpr uint8_t R24C12 = keyIndex(24, 12);
constexpr uint8_t R24C13 = keyIndex(24, 13);
constexpr uint8_t R24C14 = keyIndex(24, 14);
constexpr uint8_t R24C15 = keyIndex(24, 15);
constexpr uint8_t R24C16 = keyIndex(24, 16);
constexpr uint8_t R24C17 = keyIndex(24, 17);
constexpr uint8_t R24C18 = keyIndex(24, 18);
constexpr uint8_t R24C19 = keyIndex(24, 19);
constexpr uint8_t R24C20 = keyIndex(24, 20);
constexpr uint8_t R24C21 = keyIndex(24, 21);
constexpr uint8_t R24C22 = keyIndex(24, 22);
constexpr uint8_t R24C23 = keyIndex(24, 23);
constexpr uint8_t R24C24 = keyIndex(24, 24);
constexpr uint8_t R24C25 = keyIndex(24, 25);
constexpr uint8_t R24C26 = keyIndex(24, 26);
constexpr uint8_t R24C27 = keyIndex(24, 27);
constexpr uint8_t R24C28 = keyIndex(24, 28);
constexpr uint8_t R24C29 = keyIndex(24, 29);
constexpr uint8_t R25C0 = keyIndex(25, 0);
constexpr uint8_t R25C1 = keyIndex(25, 1);
constexpr uint8_t R25C2 = keyIndex(25, 2);
constexpr uint8_t R25C3 = keyIndex(25, 3);
constexpr uint8_t R25C4 = keyIndex(25, 4);
constexpr uint8_t R25C5 = keyIndex(25, 5);
constexpr uint8_t R25C6 = keyIndex(25, 6);
constexpr uint8_t R25C7 = keyIndex(25, 7);
constexpr uint8_t R25C8 = keyIndex(25, 8);
constexpr uint8_t R25C9 = keyIndex(25, 9);
constexpr uint8_t R25C10 = keyIndex(25, 10);
constexpr uint8_t R25C11 = keyIndex(25, 11);
constexpr uint8_t R25C12 = keyIndex(25, 12);
constexpr uint8_t R25C13 = keyIndex(25, 13);
constexpr uint8_t R25C14 = keyIndex(25, 14);
constexpr uint8_t R25C15 = keyIndex(25, 15);
constexpr uint8_t R25C16 = keyIndex(25, 16);
constexpr uint8_t R25C17 = keyIndex(25, 17);
constexpr uint8_t R25C18 = keyIndex(25, 18);
constexpr uint8_t R25C19 = keyIndex(25, 19);
constexpr uint8_t R25C20 = keyIndex(25, 20);
constexpr uint8_t R25C21 = keyIndex(25, 21);
constexpr uint8_t R25C22 = keyIndex(25, 22);
constexpr uint8_t R25C23 = keyIndex(25, 23);
constexpr uint8_t R25C24 = keyIndex(25, 24);
constexpr uint8_t R25C25 = keyIndex(25, 25);
constexpr uint8_t R25C26 = keyIndex(25, 26);
constexpr uint8_t R25C27 = keyIndex(25, 27);
constexpr uint8_t R25C28 = keyIndex(25, 28);
constexpr uint8_t R25C29 = keyIndex(25, 29);
constexpr uint8_t R26C0 = keyIndex(26, 0);
constexpr uint8_t R26C1 = keyIndex(26, 1);
constexpr uint8_t R26C2 = keyIndex(26, 2);
constexpr uint8_t R26C3 = keyIndex(26, 3);
constexpr uint8_t R26C4 = keyIndex(26, 4);
constexpr uint8_t R26C5 = keyIndex(26, 5);
constexpr uint8_t R26C6 = keyIndex(26, 6);
constexpr uint8_t R26C7 = keyIndex(26, 7);
constexpr uint8_t R26C8 = keyIndex(26, 8);
constexpr uint8_t R26C9 = keyIndex(26, 9);
constexpr uint8_t R26C10 = keyIndex(26, 10);
constexpr uint8_t R26C11 = keyIndex(26, 11);
constexpr uint8_t R26C12 = keyIndex(26, 12);
constexpr uint8_t R26C13 = keyIndex(26, 13);
constexpr uint8_t R26C14 = keyIndex(26, 14);
constexpr uint8_t R26C15 = keyIndex(26, 15);
constexpr uint8_t R26C16 = keyIndex(26, 16);
constexpr uint8_t R26C17 = keyIndex(26, 17);
constexpr uint8_t R26C18 = keyIndex(26, 18);
constexpr uint8_t R26C19 = keyIndex(26, 19);
constexpr uint8_t R26C20 = keyIndex(26, 20);
constexpr uint8_t R26C21 = keyIndex(26, 21);
constexpr uint8_t R26C22 = keyIndex(26, 22);
constexpr uint8_t R26C23 = keyIndex(26, 23);
constexpr uint8_t R26C24 = keyIndex(26, 24);
constexpr uint8_t R26C25 = keyIndex(26, 25);
constexpr uint8_t R26C26 = keyIndex(26, 26);
constexpr uint8_t R26C27 = keyIndex(26, 27);
constexpr uint8_t R26C28 = keyIndex(26, 28);
constexpr uint8_t R26C29 = keyIndex(26, 29);
constexpr uint8_t R27C0 = keyIndex(27, 0);
constexpr uint8_t R27C1 = keyIndex(27, 1);
constexpr uint8_t R27C2 = keyIndex(27, 2);
constexpr uint8_t R27C3 = keyIndex(27, 3);
constexpr uint8_t R27C4 = keyIndex(27, 4);
constexpr uint8_t R27C5 = keyIndex(27, 5);
constexpr uint8_t R27C6 = keyIndex(27, 6);
constexpr uint8_t R27C7 = keyIndex(27, 7);
constexpr uint8_t R27C8 = keyIndex(27, 8);
constexpr uint8_t R27C9 = keyIndex(27, 9);
constexpr uint8_t R27C10 = keyIndex(27, 10);
constexpr uint8_t R27C11 = keyIndex(27, 11);
constexpr uint8_t R27C12 = keyIndex(27, 12);
constexpr uint8_t R27C13 = keyIndex(27, 13);
constexpr uint8_t R27C14 = keyIndex(27, 14);
constexpr uint8_t R27C15 = keyIndex(27, 15);
constexpr uint8_t R27C16 = keyIndex(27, 16);
constexpr uint8_t R27C17 = keyIndex(27, 17);
constexpr uint8_t R27C18 = keyIndex(27, 18);
constexpr uint8_t R27C19 = keyIndex(27, 19);
constexpr uint8_t R27C20 = keyIndex(27, 20);
constexpr uint8_t R27C21 = keyIndex(27, 21);
constexpr uint8_t R27C22 = keyIndex(27, 22);
constexpr uint8_t R27C23 = keyIndex(27, 23);
constexpr uint8_t R27C24 = keyIndex(27, 24);
constexpr uint8_t R27C25 = keyIndex(27, 25);
constexpr uint8_t R27C26 = keyIndex(27, 26);
constexpr uint8_t R27C27 = keyIndex(27, 27);
constexpr uint8_t R27C28 = keyIndex(27, 28);
constexpr uint8_t R27C29 = keyIndex(27, 29);
constexpr uint8_t R28C0 = keyIndex(28, 0);
constexpr uint8_t R28C1 = keyIndex(28, 1);
constexpr uint8_t R28C2 = keyIndex(28, 2);
constexpr uint8_t R28C3 = keyIndex(28, 3);
constexpr uint8_t R28C4 = keyIndex(28, 4);
constexpr uint8_t R28C5 = keyIndex(28, 5);
constexpr uint8_t R28C6 = keyIndex(28, 6);
constexpr uint8_t R28C7 = keyIndex(28, 7);
constexpr uint8_t R28C8 = keyIndex(28, 8);
constexpr uint8_t R28C9 = keyIndex(28, 9);
constexpr uint8_t R28C10 = keyIndex(28, 10);
constexpr uint8_t R28C11 = keyIndex(28, 11);
constexpr uint8_t R28C12 = keyIndex(28, 12);
constexpr uint8_t R28C13 = keyIndex(28, 13);
constexpr uint8_t R28C14 = keyIndex(28, 14);
constexpr uint8_t R28C15 = keyIndex(28, 15);
constexpr uint8_t R28C16 = keyIndex(28, 16);
constexpr uint8_t R28C17 = keyIndex(28, 17);
constexpr uint8_t R28C18 = keyIndex(28, 18);
constexpr uint8_t R28C19 = keyIndex(28, 19);
constexpr uint8_t R28C20 = keyIndex(28, 20);
constexpr uint8_t R28C21 = keyIndex(28, 21);
constexpr uint8_t R28C22 = keyIndex(28, 22);
constexpr uint8_t R28C23 = keyIndex(28, 23);
constexpr uint8_t R28C24 = keyIndex(28, 24);
constexpr uint8_t R28C25 = keyIndex(28, 25);
constexpr uint8_t R28C26 = keyIndex(28, 26);
constexpr uint8_t R28C27 = keyIndex(28, 27);
constexpr uint8_t R28C28 = keyIndex(28, 28);
constexpr uint8_t R28C29 = keyIndex(28, 29);
constexpr uint8_t R29C0 = keyIndex(29, 0);
constexpr uint8_t R29C1 = keyIndex(29, 1);
constexpr uint8_t R29C2 = keyIndex(29, 2);
constexpr uint8_t R29C3 = keyIndex(29, 3);
constexpr uint8_t R29C4 = keyIndex(29, 4);
constexpr uint8_t R29C5 = keyIndex(29, 5);
constexpr uint8_t R29C6 = keyIndex(29, 6);
constexpr uint8_t R29C7 = keyIndex(29, 7);
constexpr uint8_t R29C8 = keyIndex(29, 8);
constexpr uint8_t R29C9 = keyIndex(29, 9);
constexpr uint8_t R29C10 = keyIndex(29, 10);
constexpr uint8_t R29C11 = keyIndex(29, 11);
constexpr uint8_t R29C12 = keyIndex(29, 12);
constexpr uint8_t R29C13 = keyIndex(29, 13);
constexpr uint8_t R29C14 = keyIndex(29, 14);
constexpr uint8_t R29C15 = keyIndex(29, 15);
constexpr uint8_t R29C16 = keyIndex(29, 16);
constexpr uint8_t R29C17 = keyIndex(29, 17);
constexpr uint8_t R29C18 = keyIndex(29, 18);
constexpr uint8_t R29C19 = keyIndex(29, 19);
constexpr uint8_t R29C20 = keyIndex(29, 20);
constexpr uint8_t R29C21 = keyIndex(29, 21);
constexpr uint8_t R29C22 = keyIndex(29, 22);
constexpr uint8_t R29C23 = keyIndex(29, 23);
constexpr uint8_t R29C24 = keyIndex(29, 24);
constexpr uint8_t R29C25 = keyIndex(29, 25);
constexpr uint8_t R29C26 = keyIndex(29, 26);
constexpr uint8_t R29C27 = keyIndex(29, 27);
constexpr uint8_t R29C28 = keyIndex(29, 28);
constexpr uint8_t R29C29 = keyIndex(29, 29);

@ -1,5 +1,5 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Planck -- OLKB Planck hardware support for Kaleidoscope
* Kaleidoscope-Hardware-OLKB-Planck -- Planck hardware support for Kaleidoscope
* Copyright (C) 2018 Keyboard.io, Inc
*
* This program is free software: you can redistribute it and/or modify
@ -18,169 +18,14 @@
#ifdef ARDUINO_AVR_PLANCK
#include <Kaleidoscope.h>
#include <KeyboardioHID.h>
#include <avr/wdt.h>
static bool do_scan_ = true;
ISR(TIMER1_OVF_vect) {
do_scan_ = true;
}
namespace kaleidoscope {
namespace hardware {
namespace olkb {
constexpr uint8_t Planck::matrix_row_pins[matrix_rows];
constexpr uint8_t Planck::matrix_col_pins[matrix_columns];
uint16_t Planck::previousKeyState_[matrix_rows];
uint16_t Planck::keyState_[matrix_rows];
uint16_t Planck::masks_[matrix_rows];
uint8_t Planck::debounce_matrix_[matrix_rows][matrix_columns];
void Planck::setup(void) {
wdt_disable();
for (uint8_t i = 0; i < sizeof(matrix_col_pins); i++) {
DDR_INPUT(matrix_col_pins[i]);
ENABLE_PULLUP(matrix_col_pins[i]);
}
for (uint8_t i = 0; i < sizeof(matrix_row_pins); i++) {
DDR_OUTPUT(matrix_row_pins[i]);
OUTPUT_HIGH(matrix_row_pins[i]);
}
/* Set up Timer1 for 500usec */
TCCR1B = _BV(WGM13);
TCCR1A = 0;
const uint32_t cycles = (F_CPU / 2000000) * 500;
ICR1 = cycles;
TCCR1B = _BV(WGM13) | _BV(CS10);
TIMSK1 = _BV(TOIE1);
}
uint16_t Planck::readCols() {
uint16_t results = 0x00 ;
for (uint8_t i = 0; i < matrix_columns; i++) {
results |= (!READ_PIN(matrix_col_pins[i]) << i);
}
return results;
}
void Planck::readMatrix() {
for (uint8_t current_row = 0; current_row < sizeof(matrix_row_pins); current_row++) {
uint16_t mask, cols;
previousKeyState_[current_row] = keyState_[current_row];
mask = debounceMaskForRow(current_row);
OUTPUT_TOGGLE(matrix_row_pins[current_row]);
cols = (readCols() & mask) | (keyState_[current_row] & ~mask);
OUTPUT_TOGGLE(matrix_row_pins[current_row]);
debounceRow(cols ^ keyState_[current_row], current_row);
keyState_[current_row] = cols;
}
}
void Planck::actOnMatrixScan() {
for (byte row = 0; row < matrix_rows; row++) {
for (byte col = 0; col < matrix_columns; col++) {
uint8_t keyState = (bitRead(previousKeyState_[row], col) << 0) |
(bitRead(keyState_[row], col) << 1);
if (keyState) {
handleKeyswitchEvent(Key_NoKey, row, col, keyState);
}
}
previousKeyState_[row] = keyState_[row];
}
}
void Planck::scanMatrix() {
if (!do_scan_)
return;
do_scan_ = false;
readMatrix();
actOnMatrixScan();
}
void Planck::maskKey(byte row, byte col) {
if (row >= matrix_rows || col >= matrix_columns)
return;
bitWrite(masks_[row], col, 1);
}
void Planck::unMaskKey(byte row, byte col) {
if (row >= matrix_rows || col >= matrix_columns)
return;
bitWrite(masks_[row], col, 0);
}
bool Planck::isKeyMasked(byte row, byte col) {
if (row >= matrix_rows || col >= matrix_columns)
return false;
return bitRead(masks_[row], col);
}
void Planck::detachFromHost() {
UDCON |= _BV(DETACH);
}
void Planck::attachToHost() {
UDCON &= ~_BV(DETACH);
}
bool Planck::isKeyswitchPressed(byte row, byte col) {
return (bitRead(keyState_[row], col) != 0);
}
bool Planck::isKeyswitchPressed(uint8_t keyIndex) {
keyIndex--;
return isKeyswitchPressed(keyIndex / matrix_columns, keyIndex % matrix_columns);
}
uint8_t Planck::pressedKeyswitchCount() {
uint8_t count = 0;
for (uint8_t r = 0; r < matrix_rows; r++) {
count += __builtin_popcount(keyState_[r]);
}
return count;
}
uint16_t Planck::debounceMaskForRow(uint8_t row) {
uint16_t result = 0;
for (uint16_t c = 0; c < matrix_columns; ++c) {
if (debounce_matrix_[row][c]) {
--debounce_matrix_[row][c];
} else {
result |= _BV(c);
}
}
return result;
}
void Planck::debounceRow(uint16_t change, uint8_t row) {
for (uint16_t i = 0; i < matrix_columns; ++i) {
if (change & _BV(i)) {
debounce_matrix_[row][i] = debounce;
}
}
}
ATMEGA_KEYBOARD_DATA(Planck);
constexpr int8_t Planck::led_count;
}
}

@ -1,5 +1,5 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Planck -- OLKB Planck hardware support for Kaleidoscope
* Kaleidoscope-Hardware-OLKB-Planck -- Planck hardware support for Kaleidoscope
* Copyright (C) 2018 Keyboard.io, Inc
*
* This program is free software: you can redistribute it and/or modify
@ -26,112 +26,21 @@
#include "kaleidoscope/macro_helpers.h"
#include "kaleidoscope/hardware/avr/pins_and_ports.h"
struct cRGB {
uint8_t r, g, b;
};
#define CRGB(r,g,b) (cRGB){b, g, r}
#include "kaleidoscope/hardware/ATMegaKeyboard.h"
namespace kaleidoscope {
namespace hardware {
namespace olkb {
class Planck {
class Planck: public kaleidoscope::hardware::ATMegaKeyboard {
public:
Planck(void) {}
static const uint8_t matrix_rows = 4;
static const uint8_t matrix_columns = 12;
static constexpr uint8_t matrix_row_pins[matrix_rows] = { PIN_D0, PIN_D5, PIN_B5, PIN_B6 };
static constexpr uint8_t matrix_col_pins[matrix_columns] = { PIN_F1, PIN_F0, PIN_B0, PIN_C7, PIN_F4, PIN_F5, PIN_F6, PIN_F7, PIN_D4, PIN_D6, PIN_B4, PIN_D7 };
static constexpr int8_t led_count = 0;
static const uint8_t debounce = 3;
void syncLeds(void) {}
void setCrgbAt(uint8_t row, byte col, cRGB color) {}
void setCrgbAt(int8_t i, cRGB crgb) {}
cRGB getCrgbAt(int8_t i) {
return CRGB(0, 0, 0);
}
int8_t getLedIndex(uint8_t row, byte col) {
return -1;
}
void scanMatrix(void);
void readMatrix(void);
void actOnMatrixScan(void);
void setup();
/** Detaching from / attaching to the host.
*
* These two functions should detach the device from (or attach it to) the
* host, preferably without rebooting the device. Their purpose is to allow
* one to do some configuration inbetween, so the re-attach happens with
* different properties. The device remains powered between these operations,
* only the connection to the host gets severed.
*/
void detachFromHost();
void attachToHost();
/* Key masking
* -----------
*
* There are situations when one wants to ignore key events for a while, and
* mask them out. These functions help do that. In isolation, they do nothing,
* plugins and the core firmware is expected to make use of these.
*
* See `handleKeyswitchEvent` in the Kaleidoscope sources for a use-case.
*/
void maskKey(uint8_t row, byte col);
void unMaskKey(uint8_t row, byte col);
bool isKeyMasked(uint8_t row, byte col);
/** Key switch states
*
* These methods offer a way to peek at the key switch states, for those cases
* where we need to deal with the state closest to the hardware. Some methods
* offer a way to check if a key is pressed, others return the number of
* pressed keys.
*/
/**
* Check if a key is pressed at a given position.
*
* @param row is the row the key is located at in the matrix.
* @param col is the column the key is located at in the matrix.
*
* @returns true if the key is pressed, false otherwise.
*/
bool isKeyswitchPressed(uint8_t row, byte col);
/**
* Check if a key is pressed at a given position.
*
* @param keyIndex is the key index, as calculated by `keyIndex`.
*
* @note Key indexes start at 1, not 0!
*
* @returns true if the key is pressed, false otherwise.
*/
bool isKeyswitchPressed(uint8_t keyIndex);
/**
* Check the number of key switches currently pressed.
*
* @returns the number of keys pressed.
*/
uint8_t pressedKeyswitchCount();
private:
ATMEGA_KEYBOARD_CONFIG(
ROW_PIN_LIST({ PIN_D0, PIN_D5, PIN_B5, PIN_B6 }),
COL_PIN_LIST({ PIN_F1, PIN_F0, PIN_B0, PIN_C7, PIN_F4, PIN_F5, PIN_F6, PIN_F7, PIN_D4, PIN_D6, PIN_B4, PIN_D7 })
);
static uint16_t previousKeyState_[matrix_rows];
static uint16_t keyState_[matrix_rows];
static uint16_t masks_[matrix_rows];
static uint8_t debounce_matrix_[matrix_rows][matrix_columns];
static uint16_t readCols();
static uint16_t debounceMaskForRow(uint8_t row);
static void debounceRow(uint16_t change, uint8_t row);
static constexpr int8_t led_count = 0;
};
#define KEYMAP( \
@ -146,76 +55,11 @@ class Planck {
{ R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11, } \
}
}
}
}
/* To be used by the hardware implementations, `keyIndex` tells us the index of
* a key, from which we can figure out the row and column as needed. The index
* starts at one, so that plugins that work with a list of key indexes can use
* zero as a sentinel. This is important, because when we initialize arrays with
* fewer elements than the declared array size, the remaining elements will be
* zero. We can use this to avoid having to explicitly add a sentinel in
* user-facing code.
*/
constexpr uint8_t keyIndex(byte row, byte col) {
return (row * kaleidoscope::hardware::olkb::Planck::matrix_columns) + col + 1;
}
/*
This oneliner will generate these constexprs:
perl -e'for($i=0;$i<6;$i++) { for ($j=0; $j<16;$j++) { print "constexpr uint8_t R${i}C${j} = keyIndex($i, $j);\n"}};'
*/
}
constexpr uint8_t R0C0 = keyIndex(0, 0);
constexpr uint8_t R0C1 = keyIndex(0, 1);
constexpr uint8_t R0C2 = keyIndex(0, 2);
constexpr uint8_t R0C3 = keyIndex(0, 3);
constexpr uint8_t R0C4 = keyIndex(0, 4);
constexpr uint8_t R0C5 = keyIndex(0, 5);
constexpr uint8_t R0C6 = keyIndex(0, 6);
constexpr uint8_t R0C7 = keyIndex(0, 7);
constexpr uint8_t R0C8 = keyIndex(0, 8);
constexpr uint8_t R0C9 = keyIndex(0, 9);
constexpr uint8_t R0C10 = keyIndex(0, 10);
constexpr uint8_t R0C11 = keyIndex(0, 11);
constexpr uint8_t R1C0 = keyIndex(1, 0);
constexpr uint8_t R1C1 = keyIndex(1, 1);
constexpr uint8_t R1C2 = keyIndex(1, 2);
constexpr uint8_t R1C3 = keyIndex(1, 3);
constexpr uint8_t R1C4 = keyIndex(1, 4);
constexpr uint8_t R1C5 = keyIndex(1, 5);
constexpr uint8_t R1C6 = keyIndex(1, 6);
constexpr uint8_t R1C7 = keyIndex(1, 7);
constexpr uint8_t R1C8 = keyIndex(1, 8);
constexpr uint8_t R1C9 = keyIndex(1, 9);
constexpr uint8_t R1C10 = keyIndex(1, 10);
constexpr uint8_t R1C11 = keyIndex(1, 11);
constexpr uint8_t R2C0 = keyIndex(2, 0);
constexpr uint8_t R2C1 = keyIndex(2, 1);
constexpr uint8_t R2C2 = keyIndex(2, 2);
constexpr uint8_t R2C3 = keyIndex(2, 3);
constexpr uint8_t R2C4 = keyIndex(2, 4);
constexpr uint8_t R2C5 = keyIndex(2, 5);
constexpr uint8_t R2C6 = keyIndex(2, 6);
constexpr uint8_t R2C7 = keyIndex(2, 7);
constexpr uint8_t R2C8 = keyIndex(2, 8);
constexpr uint8_t R2C9 = keyIndex(2, 9);
constexpr uint8_t R2C10 = keyIndex(2, 10);
constexpr uint8_t R2C11 = keyIndex(2, 11);
constexpr uint8_t R3C0 = keyIndex(3, 0);
constexpr uint8_t R3C1 = keyIndex(3, 1);
constexpr uint8_t R3C2 = keyIndex(3, 2);
constexpr uint8_t R3C3 = keyIndex(3, 3);
constexpr uint8_t R3C4 = keyIndex(3, 4);
constexpr uint8_t R3C5 = keyIndex(3, 5);
constexpr uint8_t R3C6 = keyIndex(3, 6);
constexpr uint8_t R3C7 = keyIndex(3, 7);
constexpr uint8_t R3C8 = keyIndex(3, 8);
constexpr uint8_t R3C9 = keyIndex(3, 9);
constexpr uint8_t R3C10 = keyIndex(3, 10);
constexpr uint8_t R3C11 = keyIndex(3, 11);
#include "kaleidoscope/hardware/key_indexes.h"
extern kaleidoscope::hardware::olkb::Planck &Planck;

@ -0,0 +1,98 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Technomancy-Atreus -- Atreus hardware support for Kaleidoscope
* Copyright (C) 2018 Keyboard.io, Inc
*
* Based on QMK (commit e9a67f8fd)
* (C) Jack Humbert, Phil Hagelberg, and others
* Original QMK sources:
* - keyboards/atreus/atreus.h
* - keyboards/atreus/config.h
* - quantum/matrix.c
* - tmk_core/common/avr/bootloader.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef ARDUINO_AVR_ATREUS
#include <Kaleidoscope.h>
#include <avr/wdt.h>
namespace kaleidoscope {
namespace hardware {
namespace technomancy {
ATMEGA_KEYBOARD_DATA(Atreus);
constexpr int8_t Atreus::led_count;
// Atreus-specific stuff
void Atreus::resetDevice() {
cli();
UDCON = 1;
USBCON = (1 << FRZCLK);
UCSR1B = 0;
_delay_ms(5);
EIMSK = 0;
PCICR = 0;
SPCR = 0;
ACSR = 0;
EECR = 0;
ADCSRA = 0;
TIMSK0 = 0;
TIMSK1 = 0;
TIMSK3 = 0;
TIMSK4 = 0;
UCSR1B = 0;
TWCR = 0;
DDRB = 0;
DDRC = 0;
DDRD = 0;
DDRE = 0;
DDRF = 0;
TWCR = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
PORTE = 0;
PORTF = 0;
asm volatile("jmp 0x7E00");
}
uint16_t Atreus::readCols() {
uint16_t results = 0;
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[0]) << 0);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[1]) << 1);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[2]) << 2);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[3]) << 3);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[4]) << 4);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[5]) << 5);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[6]) << 6);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[7]) << 7);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[8]) << 8);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[9]) << 9);
results |= (!READ_PIN(KeyboardHardware.matrix_col_pins[10]) << 10);
return results;
}
}
}
}
HARDWARE_IMPLEMENTATION KeyboardHardware;
kaleidoscope::hardware::technomancy::Atreus &Atreus = KeyboardHardware;
#endif

@ -0,0 +1,96 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Technomancy-Atreus -- Atreus hardware support for Kaleidoscope
* Copyright (C) 2018 Keyboard.io, Inc
*
* Based on QMK (commit e9a67f8fd)
* (C) Jack Humbert, Jun Wako, Phil Hagelberg, and others
* Original QMK sources:
* - keyboards/atreus/atreus.h
* - keyboards/atreus/config.h
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef ARDUINO_AVR_ATREUS
#include <Arduino.h>
#define HARDWARE_IMPLEMENTATION kaleidoscope::hardware::technomancy::Atreus
#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h"
#include "kaleidoscope/macro_helpers.h"
#include "kaleidoscope/hardware/ATMegaKeyboard.h"
namespace kaleidoscope {
namespace hardware {
namespace technomancy {
class Atreus: public kaleidoscope::hardware::ATMegaKeyboard {
friend class ATMegaKeyboard;
public:
Atreus(void) {}
ATMEGA_KEYBOARD_CONFIG(
ROW_PIN_LIST({PIN_D0, PIN_D1, PIN_D3, PIN_D2}),
COL_PIN_LIST({PIN_B4, PIN_B5, PIN_B6, PIN_B7, PIN_C6, PIN_D4, PIN_D6, PIN_D7, PIN_E6, PIN_F6, PIN_F7})
);
static constexpr int8_t led_count = 0;
void resetDevice();
protected:
uint16_t readCols();
};
#define KEYMAP( \
R0C0, R0C1, R0C2, R0C3, R0C4, R0C7, R0C8, R0C9, R0C10, R0C11, \
R1C0, R1C1, R1C2, R1C3, R1C4, R1C7, R1C8, R1C9, R1C10, R1C11, \
R2C0, R2C1, R2C2, R2C3, R2C4, R2C7, R2C8, R2C9, R2C10, R2C11, \
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11 \
) \
{ \
{ R0C3, R0C2, R0C7, R0C11, R0C1, XXX, R0C10, R0C0, R0C4, R0C8, R0C9 }, \
{ R1C3, R1C2, R1C7, R1C11, R1C1, XXX, R1C10, R1C0, R1C4, R1C8, R1C9 }, \
{ R2C3, R2C2, R2C7, R2C11, R2C1, R3C5, R2C10, R2C0, R2C4, R2C8, R2C9 }, \
{ R3C3, R3C2, R3C7, R3C11, R3C1, R3C6, R3C10, R3C0, R3C4, R3C8, R3C9 } \
}
#define KEYMAP_STACKED( \
R0C0, R0C1, R0C2, R0C3, R0C4, \
R1C0, R1C1, R1C2, R1C3, R1C4, \
R2C0, R2C1, R2C2, R2C3, R2C4, \
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, \
\
R0C7, R0C8, R0C9, R0C10, R0C11, \
R1C7, R1C8, R1C9, R1C10, R1C11, \
R2C7, R2C8, R2C9, R2C10, R2C11, \
R3C6, R3C7, R3C8, R3C9, R3C10, R3C11 \
) \
{ \
{ R0C3, R0C2, R0C7, R0C11, R0C1, XXX, R0C10, R0C0, R0C4, R0C8, R0C9 }, \
{ R1C3, R1C2, R1C7, R1C11, R1C1, XXX, R1C10, R1C0, R1C4, R1C8, R1C9 }, \
{ R2C3, R2C2, R2C7, R2C11, R2C1, R3C5, R2C10, R2C0, R2C4, R2C8, R2C9 }, \
{ R3C3, R3C2, R3C7, R3C11, R3C1, R3C6, R3C10, R3C0, R3C4, R3C8, R3C9 } \
}
}
}
}
#include "kaleidoscope/hardware/key_indexes.h"
extern kaleidoscope::hardware::technomancy::Atreus &Atreus;
#endif

@ -21,8 +21,6 @@
#include "kaleidoscope/key_defs.h"
#include "kaleidoscope/keyswitch_state.h"
extern const Key keymaps[][ROWS][COLS];
// Code can use this macro on injected key events to signal that
// the event isn't tied to a specific physical keyswitch

@ -20,6 +20,9 @@
#include "kaleidoscope/key_defs.h"
#include KALEIDOSCOPE_HARDWARE_H
extern const Key keymaps[][ROWS][COLS];
// Macro for defining the keymap. This should be used in the sketch
// file (*.ino) to define the keymap[] array that holds the user's
// layers. It also computes the number of layers in that keymap.

@ -135,3 +135,6 @@ int array[] = { A, B, RESTRICT_ARGS_COUNT(C, 3, B_MACRO, ##__VA_ARGS__) };
}){}, /* End of dummy lambda, the comma operator's A operand. */ __NL__ \
B /* The overall ASSERT_ARGS_COUNT evaluates to B. */ __NL__ \
)
/* Count the args in a list */
#define NUM_ARGS(...) (sizeof((int[])__VA_ARGS__)/sizeof(int))

Loading…
Cancel
Save