void Code_LayerHold::press() | void Code_LayerHold::press() | ||||
{ | { | ||||
refLayerState.hold(layer); | |||||
refLayerState.hold(layerId); | |||||
} | } | ||||
void Code_LayerHold::release() | void Code_LayerHold::release() | ||||
{ | { | ||||
refLayerState.unhold(layer); | |||||
refLayerState.unhold(layerId); | |||||
} | } |
class Code_LayerHold : public Code | class Code_LayerHold : public Code | ||||
{ | { | ||||
private: | private: | ||||
const uint8_t layer; | |||||
const uint8_t layerId; | |||||
LayerState& refLayerState; | LayerState& refLayerState; | ||||
public: | public: | ||||
Code_LayerHold(const uint8_t layer, LayerState& refLayerState) | |||||
: layer(layer), refLayerState(refLayerState) {} | |||||
Code_LayerHold(const uint8_t layerId, LayerState& refLayerState) | |||||
: layerId(layerId), refLayerState(refLayerState) {} | |||||
virtual void press(); | virtual void press(); | ||||
virtual void release(); | virtual void release(); | ||||
}; | }; |
void Code_LayerLock::press() | void Code_LayerLock::press() | ||||
{ | { | ||||
refLayerState.lock(layer); | |||||
refLayerState.lock(layerId); | |||||
} | } | ||||
void Code_LayerLock::release() | void Code_LayerLock::release() |
class Code_LayerLock : public Code | class Code_LayerLock : public Code | ||||
{ | { | ||||
private: | private: | ||||
const uint8_t layer; | |||||
const uint8_t layerId; | |||||
LayerState& refLayerState; | LayerState& refLayerState; | ||||
public: | public: | ||||
Code_LayerLock(const uint8_t layer, LayerState& refLayerState) | |||||
: layer(layer), refLayerState(refLayerState) {} | |||||
Code_LayerLock(const uint8_t layerId, LayerState& refLayerState) | |||||
: layerId(layerId), refLayerState(refLayerState) {} | |||||
virtual void press(); | virtual void press(); | ||||
virtual void release(); | virtual void release(); | ||||
}; | }; |
void Key_LayeredCodeSc::press() | void Key_LayeredCodeSc::press() | ||||
{ | { | ||||
layer = refLayerState.getActiveLayer(); | |||||
layerId = refLayerState.getActiveLayer(); | |||||
pressCode(); | pressCode(); | ||||
} | } |
/* Class Key_LayeredCodeSc is a 2-layer code, one object for each layer e.g. | /* Class Key_LayeredCodeSc is a 2-layer code, one object for each layer e.g. | ||||
layer0: ms_up //mouse up | layer0: ms_up //mouse up | ||||
layer1: KEY_UP //up arrow | layer1: KEY_UP //up arrow | ||||
When the key is pressed, the active layer is retrieved from refLayerState, | |||||
When the key is pressed, the active layerId is retrieved from refLayerState, | |||||
and the object for the active layer is sent to USB. | and the object for the active layer is sent to USB. | ||||
*/ | */ | ||||
class Key_LayeredCodeSc : public Key_LayeredCodeScBase | class Key_LayeredCodeSc : public Key_LayeredCodeScBase |
void Key_LayeredCodeScBase::pressCode() | void Key_LayeredCodeScBase::pressCode() | ||||
{ | { | ||||
if (layer) | |||||
if (layerId) | |||||
{ | { | ||||
Keyboard.press(scancode1); | Keyboard.press(scancode1); | ||||
} | } | ||||
void Key_LayeredCodeScBase::release() | void Key_LayeredCodeScBase::release() | ||||
{ | { | ||||
if (layer) | |||||
if (layerId) | |||||
{ | { | ||||
Keyboard.release(scancode1); | Keyboard.release(scancode1); | ||||
} | } |
#include <inttypes.h> | #include <inttypes.h> | ||||
#include "Code.h" | #include "Code.h" | ||||
/* Class Key_LayeredCodeScBase is a 2-layer code, with one object for each layer e.g. | |||||
layer0: ms_up //mouse up | |||||
layer1: KEY_UP //up arrow | |||||
When the key is pressed, the active layer is retrieved from refLayerState, | |||||
and the object for the active layer is sent to USB. | |||||
/* Class Key_LayeredCodeScBase is an abstract base class for 2-layer keys: | |||||
if layerId=0, send code0 | |||||
if layerId=1, send scancode1 | |||||
*/ | */ | ||||
class Key_LayeredCodeScBase : public Code | class Key_LayeredCodeScBase : public Code | ||||
{ | { | ||||
Code& refCode0; | Code& refCode0; | ||||
const uint16_t scancode1; | const uint16_t scancode1; | ||||
protected: | protected: | ||||
bool layer; | |||||
bool layerId; //active layer when key was pressed, 0 or 1 | |||||
public: | public: | ||||
Key_LayeredCodeScBase(Code& refCode0, const uint16_t scancode1, uint8_t layer): | |||||
refCode0(refCode0), scancode1(scancode1), layer(layer) { } | |||||
Key_LayeredCodeScBase(Code& refCode0, const uint16_t scancode1, uint8_t layerId): | |||||
refCode0(refCode0), scancode1(scancode1), layerId(layerId) { } | |||||
virtual void press()=0; | virtual void press()=0; | ||||
virtual void release(); | virtual void release(); | ||||
virtual void pressCode(); | virtual void pressCode(); |
void Key_LayeredKeys::press() | void Key_LayeredKeys::press() | ||||
{ | { | ||||
layer = refLayerState.getActiveLayer(); | |||||
layerId = refLayerState.getActiveLayer(); | |||||
ptrsKeys[layer]->press(); | |||||
ptrsKeys[layerId]->press(); | |||||
} | } | ||||
void Key_LayeredKeys::release() | void Key_LayeredKeys::release() | ||||
{ | { | ||||
ptrsKeys[layer]->release(); | |||||
ptrsKeys[layerId]->release(); | |||||
} | } |
/* Class Key_LayeredKeys contains an array of Key pointers, one pointer per layer. | /* Class Key_LayeredKeys contains an array of Key pointers, one pointer per layer. | ||||
Codes are a kind of Key, so the Key pointers can point to Codes or Keys. | Codes are a kind of Key, so the Key pointers can point to Codes or Keys. | ||||
When the key is pressed, active layer is retreived from refLayerState and | |||||
the Key object of the active layer is called. | |||||
When the key is pressed, active layerId is retreived from refLayerState and | |||||
the Key object of the active layerId is called. | |||||
*/ | */ | ||||
class Key_LayeredKeys : public Key | class Key_LayeredKeys : public Key | ||||
{ | { | ||||
private: | private: | ||||
Key*const *const ptrsKeys; //array of Key pointers, one Key per layer | Key*const *const ptrsKeys; //array of Key pointers, one Key per layer | ||||
uint8_t layer; //active layer when key was pressed | |||||
uint8_t layerId; //active layer when key was pressed | |||||
static LayerStateInterface& refLayerState; | static LayerStateInterface& refLayerState; | ||||
public: | public: | ||||
Key_LayeredKeys(Key* const ptrsKeys[]): ptrsKeys(ptrsKeys) {} | Key_LayeredKeys(Key* const ptrsKeys[]): ptrsKeys(ptrsKeys) {} |
void Key_LayeredScSc::press() | void Key_LayeredScSc::press() | ||||
{ | { | ||||
layer = refLayerState.getActiveLayer(); | |||||
layerId = refLayerState.getActiveLayer(); | |||||
pressScancode(); | pressScancode(); | ||||
} | } |
#include <Key_LayeredScScBase.h> | #include <Key_LayeredScScBase.h> | ||||
/* Class Key_LayeredScSc is composed of two scancodes; "S" stands for Scancode. | /* Class Key_LayeredScSc is composed of two scancodes; "S" stands for Scancode. | ||||
layer is retreived from refLayerState. | |||||
when layer=0, press sends scancode0 | |||||
when layer=1, press sends scancode1 | |||||
layerId is retreived from refLayerState. | |||||
when layerId=0, press sends scancode0 | |||||
when layerId=1, press sends scancode1 | |||||
*/ | */ | ||||
class Key_LayeredScSc : public Key_LayeredScScBase | class Key_LayeredScSc : public Key_LayeredScScBase | ||||
{ | { |
void Key_LayeredScScBase::pressScancode() | void Key_LayeredScScBase::pressScancode() | ||||
{ | { | ||||
if (layer) | |||||
if (layerId) | |||||
{ | { | ||||
scancode = scancode1; | scancode = scancode1; | ||||
} | } |
#include <inttypes.h> | #include <inttypes.h> | ||||
#include "Code.h" | #include "Code.h" | ||||
/* Class Key_LayeredScScBase is an abstract base class. It is composed of two scancodes: | |||||
if layer=0, send scancode0 | |||||
if layer=1, send scancode1 | |||||
/* Class Key_LayeredScScBase is an abstract base class for 2-layer keys: | |||||
if layerId=0, send scancode0 | |||||
if layerId=1, send scancode1 | |||||
*/ | */ | ||||
class Key_LayeredScScBase : public Code | class Key_LayeredScScBase : public Code | ||||
{ | { | ||||
const uint16_t scancode1; | const uint16_t scancode1; | ||||
uint16_t scancode; | uint16_t scancode; | ||||
protected: | protected: | ||||
bool layer; //0 or 1 | |||||
bool layerId; //active layer when key was pressed, 0 or 1 | |||||
public: | public: | ||||
Key_LayeredScScBase(const uint16_t scancode0, const uint16_t scancode1): | Key_LayeredScScBase(const uint16_t scancode0, const uint16_t scancode1): | ||||
scancode0(scancode0), scancode1(scancode1), layer(0) { } | |||||
scancode0(scancode0), scancode1(scancode1), layerId(0) { } | |||||
virtual void press()=0; | virtual void press()=0; | ||||
virtual void release(); | virtual void release(); | ||||
void pressScancode(); | void pressScancode(); |
#include "LayerState.h" | #include "LayerState.h" | ||||
void LayerState::hold(const uint8_t layer) | |||||
void LayerState::hold(const uint8_t layerId) | |||||
{ | { | ||||
setActiveLayer(layer); | |||||
setActiveLayer(layerId); | |||||
} | } | ||||
void LayerState::unhold(const uint8_t layer) | |||||
void LayerState::unhold(const uint8_t layerId) | |||||
{ | { | ||||
if (layer == activeLayer); | |||||
if (layerId == activeLayer); | |||||
{ | { | ||||
setActiveLayer(lockedLayer); | setActiveLayer(lockedLayer); | ||||
} | } | ||||
} | } | ||||
void LayerState::lock(const uint8_t layer) | |||||
void LayerState::lock(const uint8_t layerId) | |||||
{ | { | ||||
setActiveLayer(layer); | |||||
lockedLayer = layer; | |||||
setActiveLayer(layerId); | |||||
lockedLayer = layerId; | |||||
} | } | ||||
/*Derived classes override setActiveLayer() to also set LED indicator lights e.g. LayerState_LED | /*Derived classes override setActiveLayer() to also set LED indicator lights e.g. LayerState_LED | ||||
*/ | */ | ||||
void LayerState::setActiveLayer(const uint8_t layer) | |||||
void LayerState::setActiveLayer(const uint8_t layerId) | |||||
{ | { | ||||
activeLayer = layer; | |||||
activeLayer = layerId; | |||||
} | } | ||||
uint8_t LayerState::getActiveLayer() | uint8_t LayerState::getActiveLayer() |
protected: | protected: | ||||
uint8_t activeLayer; //currently active layer | uint8_t activeLayer; //currently active layer | ||||
uint8_t lockedLayer; //most recently pressed lock layer | uint8_t lockedLayer; //most recently pressed lock layer | ||||
virtual void setActiveLayer(const uint8_t layer); | |||||
virtual void setActiveLayer(const uint8_t layerId); | |||||
public: | public: | ||||
LayerState() : activeLayer(0), lockedLayer(0) {} | LayerState() : activeLayer(0), lockedLayer(0) {} | ||||
virtual void hold(uint8_t layer); //set activeLayer | |||||
virtual void unhold(const uint8_t layer); //restore activeLayer to lockedLayer | |||||
virtual void lock(uint8_t layer); //set activeLayer and lock it | |||||
virtual void hold(uint8_t layerId); //set activeLayer | |||||
virtual void unhold(const uint8_t layerId); //restore activeLayer to lockedLayer | |||||
virtual void lock(uint8_t layerId); //set activeLayer and lock it | |||||
virtual uint8_t getActiveLayer(); | virtual uint8_t getActiveLayer(); | ||||
}; | }; | ||||
#endif | #endif |
ptrsLEDs[getActiveLayer()]->on(); | ptrsLEDs[getActiveLayer()]->on(); | ||||
} | } | ||||
void LayerState_LED::setActiveLayer(const uint8_t layer) | |||||
void LayerState_LED::setActiveLayer(const uint8_t layerId) | |||||
{ | { | ||||
ptrsLEDs[activeLayer]->off(); | ptrsLEDs[activeLayer]->off(); | ||||
activeLayer = layer; | |||||
activeLayer = layerId; | |||||
ptrsLEDs[activeLayer]->on(); | ptrsLEDs[activeLayer]->on(); | ||||
} | } |
class LayerState_LED : public LayerState | class LayerState_LED : public LayerState | ||||
{ | { | ||||
private: | private: | ||||
LED*const *const ptrsLEDs; //array of LEDs, where layer id is array index | |||||
virtual void setActiveLayer(const uint8_t layer); //set active layer and turn on it's LED | |||||
LED*const *const ptrsLEDs; //array of LEDs, where layerId is array index | |||||
virtual void setActiveLayer(const uint8_t layerId);//set active layerId and turn on it's LED | |||||
public: | public: | ||||
LayerState_LED(LED*const ptrsLEDs[]): ptrsLEDs(ptrsLEDs) {} | LayerState_LED(LED*const ptrsLEDs[]): ptrsLEDs(ptrsLEDs) {} | ||||
void begin(); | void begin(); |
/* keybrd_3_multi-layer_annotated.ino | |||||
/* keybrd_3a_multi-layerHold.ino | |||||
This sketch: | This sketch: | ||||
is firmware for a simple 2-layer keyboard | is firmware for a simple 2-layer keyboard | ||||
The CODES section instantiates six codes, one for each item in the layout. | The CODES section instantiates six codes, one for each item in the layout. | ||||
*/ | */ | ||||
/* ---------------- LAYER CODE ----------------- | /* ---------------- LAYER CODE ----------------- | ||||
enum assigns id numbers to the layers. | |||||
enum assigns layerId numbers to the layers. | |||||
*/ | */ | ||||
enum layers { NORMAL, FN }; | enum layers { NORMAL, FN }; | ||||
LayerState layerState; | LayerState layerState; | ||||
/* | /* | ||||
NORMAL=0 and FN=1. LayerState's default layer id is 0. | |||||
NORMAL=0 and FN=1. LayerState's default layerId is 0. | |||||
The Code_LayerHold constructor has two parameters: | The Code_LayerHold constructor has two parameters: | ||||
1) the layer that will be active while the key is held down | |||||
1) the layerId that will be active while the key is held down | |||||
2) a LayerState that will keep track of the active layer | 2) a LayerState that will keep track of the active layer | ||||
When l_fn is pressed, it tells layerState to change the active layer to 1. | When l_fn is pressed, it tells layerState to change the active layer to 1. | ||||
When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer. | When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer. | ||||
Key_LayeredKeys k_11(ptrsCodes_11); | Key_LayeredKeys k_11(ptrsCodes_11); | ||||
/* Key_LayeredKeys has a reference to layerState. | /* Key_LayeredKeys has a reference to layerState. | ||||
Thus Key_LayeredKeys can call layerState to get the active layer id. | |||||
Thus Key_LayeredKeys can call layerState to get the active layerId. | |||||
*/ | */ | ||||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | ||||
/* keybrd_3b_layerLock.ino | |||||
This sketch: | |||||
is firmware for a simple 2-layer keyboard | |||||
runs on the first two rows and columns of a breadboard keyboard | |||||
| Layout | **0** | **1** | | |||||
|:------:|:-----:|:-----:| | |||||
| **0** | a [ | b ] | | |||||
| **1** |normal | sym | | |||||
normal layer keys are a b c | |||||
sym layer keys are brackets [ ] and num | |||||
num layer keys are 6 7 | |||||
The num layer key is located on the sym layer | |||||
num layer is active while holding sym+num | |||||
Each cell in the table's body represents a key. | |||||
The layered keys in column 1 have two layers; one character for each layer. | |||||
Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are on the fn layer. | |||||
Holding the fn key down makes it the active layer. Releasing the fn key restores the normal layer. | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
//Keys | |||||
#include <Code_Sc.h> | |||||
//#include <Code_ScS.h> | |||||
//#include <Code_Null.h> | |||||
#include <LayerState.h> | |||||
#include <Code_LayerLock.h> | |||||
#include <Code_LayerHold.h> | |||||
#include <Key_LayeredKeys.h> | |||||
//Matrix | |||||
#include <Row.h> | |||||
#include <Scanner_uC.h> | |||||
#include <ScanDelay.h> | |||||
// ============ SPEED CONFIGURATION ============ | |||||
ScanDelay scanDelay(9000); | |||||
// ================== SCANNER ================== | |||||
uint8_t readPins[] = {14, 15}; | |||||
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||||
Scanner_uC scanner(LOW, readPins, readPinCount); | |||||
/* =================== CODES =================== | |||||
The CODES section instantiates six codes, one for each item in the layout. | |||||
*/ | |||||
/* ---------------- LAYER CODE ----------------- | |||||
enum assigns layerId numbers to the layers. | |||||
*/ | |||||
enum layers { NORMAL, SYM }; | |||||
/* layerState keeps track of the active layer. | |||||
*/ | |||||
LayerState layerState; | |||||
/* | |||||
NORMAL=0 and FN=1. LayerState's default layerId is 0. | |||||
The Code_LayerHold constructor has two parameters: | |||||
1) the layerId that will be active while the key is held down | |||||
2) a LayerState that will keep track of the active layer | |||||
When l_fn is pressed, it tells layerState to change the active layer to 1. | |||||
When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer. | |||||
*/ | |||||
Code_LayerLock l_normal(NORMAL, layerState); | |||||
Code_LayerLock l_sym(SYM, layerState); | |||||
// ---------------- SCAN CODES ----------------- | |||||
Code_Sc s_a(KEY_A); | |||||
Code_Sc s_b(KEY_B); | |||||
Code_Sc s_leftBracket(KEY_LEFT_BRACE); //[ ("brace" means curly bracket {}) | |||||
Code_Sc s_rightBracket(KEY_RIGHT_BRACE); //] | |||||
//Code_Null code_null; | |||||
/* =================== KEYS ==================== | |||||
Here we pack Codes into keys. | |||||
The Key_LayeredKeys constructor takes one array of Code pointers - one Code object per layer. | |||||
The Key object names in this sketch start with a "k_" followed by row-column coordinates. | |||||
*/ | |||||
Key* const ptrsCodes_00[] = { &s_a, &s_leftBracket }; | |||||
Key_LayeredKeys k_00(ptrsCodes_00); | |||||
Key* const ptrsCodes_01[] = { &s_b, &s_rightBracket }; | |||||
Key_LayeredKeys k_01(ptrsCodes_01); | |||||
/* Key_LayeredKeys has a reference to layerState. | |||||
Thus Key_LayeredKeys can call layerState to get the active layerId. | |||||
*/ | |||||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||||
/* HOW LAYERED OBJECTS WORK | |||||
When a Key_LayeredKeys object is pressed, it gets the active layer id from layerState. | |||||
It then uses the layer id as an array index to call the Code of the active layer. | |||||
The Code object then sends its scancode over USB. | |||||
*/ | |||||
/* =================== ROWS ==================== | |||||
Here we pack Key pointers into row objects. | |||||
Codes are a kind of Key that only have one layer. | |||||
So rows can contain a mix of codes and multi-layered keys. | |||||
Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Code pointers and Key pointers. | |||||
*/ | |||||
Key* const ptrsKeys_0[] = { &k_00, &k_01 }; | |||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||||
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0); | |||||
Key* const ptrsKeys_1[] = { &l_normal, &l_sym }; | |||||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1); | |||||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
} | |||||
void loop() | |||||
{ | |||||
row_0.process(); | |||||
row_1.process(); | |||||
scanDelay.delay(); | |||||
} |
/* keybrd_3c_sublayerNull.ino | |||||
This sketch: | |||||
is firmware for a simple 2-layer keyboard | |||||
runs on the first two rows and columns of a breadboard keyboard | |||||
| Layout | **0** | **1** | **2** | | |||||
|:------:|:-----:|:-----:|:-----:| | |||||
| **0** | a - 1 | b = | c Num | | |||||
| **1** |Normal | Sym | Enter | | |||||
normal layer keys are a b c | |||||
sym layer keys are brackets [ ] and num | |||||
num layer keys are 6 7 | |||||
The num layer key is located on the sym layer | |||||
num layer is active while holding sym+num | |||||
Each cell in the table's body represents a key. | |||||
The layered keys in column 1 have two layers; one character for each layer. | |||||
Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are on the fn layer. | |||||
Holding the fn key down makes it the active layer. Releasing the fn key restores the normal layer. | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
//Keys | |||||
#include <Code_Sc.h> | |||||
#include <Code_Null.h> | |||||
#include <LayerState.h> | |||||
#include <Code_LayerLock.h> | |||||
#include <Code_LayerHold.h> | |||||
#include <Key_LayeredKeys.h> | |||||
//Matrix | |||||
#include <Row.h> | |||||
#include <Scanner_uC.h> | |||||
#include <ScanDelay.h> | |||||
// ============ SPEED CONFIGURATION ============ | |||||
ScanDelay scanDelay(9000); | |||||
// ================== SCANNER ================== | |||||
uint8_t readPins[] = {14, 15, 16}; | |||||
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||||
Scanner_uC scanner(LOW, readPins, readPinCount); | |||||
/* =================== CODES =================== | |||||
The CODES section instantiates six codes, one for each item in the layout. | |||||
*/ | |||||
/* ---------------- LAYER CODE ----------------- | |||||
enum assigns layerId numbers to the layers. | |||||
*/ | |||||
enum layers { NORMAL, SYM, NUM }; | |||||
/* layerState keeps track of the active layer. | |||||
*/ | |||||
LayerState layerState; | |||||
/* | |||||
NORMAL=0 and FN=1. LayerState's default layerId is 0. | |||||
The Code_LayerHold constructor has two parameters: | |||||
1) the layerId that will be active while the key is held down | |||||
2) a LayerState that will keep track of the active layer | |||||
When l_fn is pressed, it tells layerState to change the active layer to 1. | |||||
When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer. | |||||
*/ | |||||
Code_LayerLock l_normal(NORMAL, layerState); | |||||
Code_LayerLock l_sym(SYM, layerState); | |||||
Code_LayerHold l_num(NUM, layerState); | |||||
// ---------------- SCAN CODES ----------------- | |||||
Code_Sc s_a(KEY_A); | |||||
Code_Sc s_b(KEY_B); | |||||
Code_Sc s_c(KEY_C); | |||||
Code_Sc s_minus(KEY_MINUS); | |||||
Code_Sc s_equal(KEY_EQUAL); | |||||
Code_Sc s_enter(KEY_ENTER); | |||||
Code_Sc s_1(KEY_1); | |||||
Code_Null code_null; | |||||
/* =================== KEYS ==================== | |||||
Here we pack Codes into keys. | |||||
The Key_LayeredKeys constructor takes one array of Code pointers - one Code object per layer. | |||||
The Key object names in this sketch start with a "k_" followed by row-column coordinates. | |||||
*/ | |||||
Key* const ptrsCodes_00[] = { &s_a, &s_minus, &s_1 }; | |||||
Key_LayeredKeys k_00(ptrsCodes_00); | |||||
Key* const ptrsCodes_01[] = { &s_b, &s_equal, &s_equal }; | |||||
Key_LayeredKeys k_01(ptrsCodes_01); | |||||
Key* const ptrsCodes_02[] = { &s_c, &l_num, &code_null }; | |||||
Key_LayeredKeys k_02(ptrsCodes_02); | |||||
/* Key_LayeredKeys has a reference to layerState. | |||||
Thus Key_LayeredKeys can call layerState to get the active layerId. | |||||
*/ | |||||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||||
/* HOW LAYERED OBJECTS WORK | |||||
When a Key_LayeredKeys object is pressed, it gets the active layer id from layerState. | |||||
It then uses the layer id as an array index to call the Code of the active layer. | |||||
The Code object then sends its scancode over USB. | |||||
*/ | |||||
/* =================== ROWS ==================== | |||||
Here we pack Key pointers into row objects. | |||||
Codes are a kind of Key that only have one layer. | |||||
So rows can contain a mix of codes and multi-layered keys. | |||||
Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Code pointers and Key pointers. | |||||
*/ | |||||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 }; | |||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||||
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0); | |||||
Key* const ptrsKeys_1[] = { &l_normal, &l_sym, &s_enter }; | |||||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1); | |||||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
} | |||||
void loop() | |||||
{ | |||||
row_0.process(); | |||||
row_1.process(); | |||||
scanDelay.delay(); | |||||
} |
/* keybrd_3d_sublayerNested.ino | |||||
This sketch: | |||||
is firmware for a simple 2-layer keyboard | |||||
runs on the first two rows and columns of a breadboard keyboard | |||||
| Layout | **0** | **1** | **2** | | |||||
|:------:|:-----:|:-----:|:-----:| | |||||
| **0** | a - 1 | b = | c Num | | |||||
| **1** |Normal | Sym | Enter | | |||||
normal layer keys are a b c | |||||
sym layer keys are brackets [ ] and num | |||||
num layer keys are 6 7 | |||||
The num layer key is located on the sym layer | |||||
num layer is active while holding sym+num | |||||
Each cell in the table's body represents a key. | |||||
The layered keys in column 1 have two layers; one character for each layer. | |||||
Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are on the fn layer. | |||||
Holding the fn key down makes it the active layer. Releasing the fn key restores the normal layer. | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
//Keys | |||||
#include <Code_Sc.h> | |||||
#include <Code_Null.h> | |||||
#include <LayerState.h> | |||||
#include <Code_LayerLock.h> | |||||
#include <Code_LayerHold.h> | |||||
#include <Key_LayeredKeys.h> | |||||
#include <Key_LayeredScSc.h> | |||||
//Matrix | |||||
#include <Row.h> | |||||
#include <Scanner_uC.h> | |||||
#include <ScanDelay.h> | |||||
// ============ SPEED CONFIGURATION ============ | |||||
ScanDelay scanDelay(9000); | |||||
// ================== SCANNER ================== | |||||
uint8_t readPins[] = {14, 15, 16}; | |||||
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||||
Scanner_uC scanner(LOW, readPins, readPinCount); | |||||
/* =================== CODES =================== | |||||
The CODES section instantiates six codes, one for each item in the layout. | |||||
*/ | |||||
/* ---------------- LAYER CODE ----------------- | |||||
enum assigns layerId numbers to the layers. | |||||
*/ | |||||
enum layers { NORMAL, SYM }; | |||||
/* layerState keeps track of the active layer. | |||||
*/ | |||||
LayerState layerState; | |||||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||||
/* | |||||
NORMAL=0 and FN=1. LayerState's default layerId is 0. | |||||
The Code_LayerHold constructor has two parameters: | |||||
1) the layerId that will be active while the key is held down | |||||
2) a LayerState that will keep track of the active layer | |||||
When l_fn is pressed, it tells layerState to change the active layer to 1. | |||||
When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer. | |||||
*/ | |||||
Code_LayerLock l_normal(NORMAL, layerState); | |||||
Code_LayerLock l_sym(SYM, layerState); | |||||
//sublayer | |||||
enum subLayers { SUBSYM, SUBNUM }; | |||||
LayerState sublayerState; | |||||
Code_LayerHold l_num(SUBNUM, sublayerState); | |||||
LayerStateInterface& Key_LayeredScSc::refLayerState = sublayerState; | |||||
// ---------------- SCAN CODES ----------------- | |||||
Code_Sc s_a(KEY_A); | |||||
Code_Sc s_b(KEY_B); | |||||
Code_Sc s_c(KEY_C); | |||||
Code_Sc s_minus(KEY_MINUS); | |||||
Code_Sc s_equal(KEY_EQUAL); | |||||
Code_Sc s_enter(KEY_ENTER); | |||||
Code_Sc s_1(KEY_1); | |||||
Code_Null code_null; | |||||
/* =================== KEYS ==================== | |||||
Here we pack Codes into keys. | |||||
The Key_LayeredKeys constructor takes one array of Code pointers - one Code object per layer. | |||||
The Key object names in this sketch start with a "k_" followed by row-column coordinates. | |||||
*/ | |||||
Key_LayeredScSc sub_00(KEY_MINUS, KEY_1); | |||||
Key* const ptrsCodes_00[] = { &s_a, &sub_00 }; | |||||
Key_LayeredKeys k_00(ptrsCodes_00); | |||||
Key* const ptrsCodes_01[] = { &s_b, &s_equal }; | |||||
Key_LayeredKeys k_01(ptrsCodes_01); | |||||
Key* const ptrsCodes_02[] = { &s_c, &l_num }; | |||||
Key_LayeredKeys k_02(ptrsCodes_02); | |||||
/* HOW LAYERED OBJECTS WORK | |||||
When a Key_LayeredKeys object is pressed, it gets the active layer id from layerState. | |||||
It then uses the layer id as an array index to call the Code of the active layer. | |||||
The Code object then sends its scancode over USB. | |||||
*/ | |||||
/* =================== ROWS ==================== | |||||
Here we pack Key pointers into row objects. | |||||
Codes are a kind of Key that only have one layer. | |||||
So rows can contain a mix of codes and multi-layered keys. | |||||
Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Code pointers and Key pointers. | |||||
*/ | |||||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 }; | |||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||||
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0); | |||||
Key* const ptrsKeys_1[] = { &l_normal, &l_sym, &s_enter }; | |||||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1); | |||||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
} | |||||
void loop() | |||||
{ | |||||
row_0.process(); | |||||
row_1.process(); | |||||
scanDelay.delay(); | |||||
} |
/* keybrd_3_autoShift_annotated.ino | |||||
/* keybrd_3b_autoShift.ino | |||||
This sketch: | This sketch: | ||||
is a simple 2-layer keyboard with AutoShift | is a simple 2-layer keyboard with AutoShift | ||||
#include <Key_LayeredKeys.h> | #include <Key_LayeredKeys.h> | ||||
//Matrix | //Matrix | ||||
#include <Row_uC.h> | |||||
#include <Row.h> | |||||
#include <Scanner_uC.h> | |||||
#include <ScanDelay.h> | #include <ScanDelay.h> | ||||
// ============ SPEED CONFIGURATION ============ | // ============ SPEED CONFIGURATION ============ | ||||
ScanDelay scanDelay(9000); | ScanDelay scanDelay(9000); | ||||
// ================ ACTIVE STATE =============== | |||||
const bool Scanner_uC::STROBE_ON = LOW; | |||||
const bool Scanner_uC::STROBE_OFF = HIGH; | |||||
// =================== PINS ==================== | |||||
// ================== SCANNER ================== | |||||
uint8_t readPins[] = {14, 15}; | uint8_t readPins[] = {14, 15}; | ||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||||
Scanner_uC scanner(LOW, readPins, readPinCount); | |||||
// =================== CODES =================== | // =================== CODES =================== | ||||
// ---------------- LAYER CODE ----------------- | // ---------------- LAYER CODE ----------------- | ||||
// =================== ROWS ==================== | // =================== ROWS ==================== | ||||
Key* const ptrsKeys_0[] = { &s_shift, &k_01 }; | Key* const ptrsKeys_0[] = { &s_shift, &k_01 }; | ||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | |||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||||
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0); | |||||
//Row row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | |||||
Key* const ptrsKeys_1[] = { &l_fn, &k_11 }; | Key* const ptrsKeys_1[] = { &l_fn, &k_11 }; | ||||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); | |||||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1); | |||||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1); | |||||
//Row row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); | |||||
// ################### MAIN #################### | // ################### MAIN #################### | ||||
void setup() | void setup() |
Tutorial 2 - single-layer keyboard | Tutorial 2 - single-layer keyboard | ||||
======================================= | ======================================= | ||||
The easiest way to learn the keyboard library is to read some simple sketches. | The easiest way to learn the keyboard library is to read some simple sketches. | ||||
[keybrd_2_single-layer_annotated.ino](keybrd_2_single-layer_annotated/keybrd_2_single-layer_annotated.ino) is a simple sketch with annotations that explain how a keybrd sketch works. | |||||
[keybrd_2_single-layer.ino](keybrd_2_single-layer/keybrd_2_single-layer.ino) is a simple sketch with annotations that explain how a keybrd sketch works. | |||||
The sketch will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) | The sketch will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) | ||||
After reading the sketch you will be able to modify it to suite your own single-layer keyboard design. | After reading the sketch you will be able to modify it to suite your own single-layer keyboard design. |
The following pseudo code is of three keybrd library classes. | The following pseudo code is of three keybrd library classes. | ||||
It has just enough detail to show the internal workings of layer schemes. | It has just enough detail to show the internal workings of layer schemes. | ||||
**Code_Layer** objects change the active layer when pressed. | |||||
The "layer" variable is a layer id number. | |||||
**Code_Layer** objects change the active layer. | |||||
When a Code_Layer object is pressed, it tells LayerState to update the active layer. | When a Code_Layer object is pressed, it tells LayerState to update the active layer. | ||||
``` | ``` | ||||
class Code_Layer | class Code_Layer | ||||
{ | { | ||||
int layer; | |||||
int layerId; | |||||
LayerState& refLayerState; | LayerState& refLayerState; | ||||
press() { refLayerState.setActiveLayer(layer); } | |||||
press() { refLayerState.setActiveLayer(layerId); } | |||||
}; | }; | ||||
``` | ``` | ||||
**LayerState** objects keep track of the active layer. | |||||
**LayerState** objects keep track of the activeLayer. | |||||
A LayerState's activeLayer is always up to date. | A LayerState's activeLayer is always up to date. | ||||
``` | ``` | ||||
class LayerState | class LayerState | ||||
{ | { | ||||
int activeLayer; | int activeLayer; | ||||
setActiveLayer(int layer) { activeLayer = layer; } | |||||
setActiveLayer(int layerId) { activeLayer = layerId; } | |||||
getActiveLayer() { return activeLayer; } | getActiveLayer() { return activeLayer; } | ||||
}; | }; | ||||
``` | ``` | ||||
**Key_LayeredKeys** objects contain an array of keys, one key for each layer. | **Key_LayeredKeys** objects contain an array of keys, one key for each layer. | ||||
Key_LayeredKeys objects use layer ids as Key_LayeredKeys indexes. | |||||
When a Key_LayeredKeys object is pressed, it gets the active layer from LayerState, and sends the corresponding key. | |||||
Key_LayeredKeys objects use layerIds as Key_LayeredKeys indexes. | |||||
When a Key_LayeredKeys object is pressed, it gets the active layerId from LayerState, and sends the corresponding key. | |||||
``` | ``` | ||||
class Key_LayeredKeys | class Key_LayeredKeys | ||||
{ | { | ||||
Key** ptrsKeys; //array of Key pointers, one Key pointer per layer | Key** ptrsKeys; //array of Key pointers, one Key pointer per layer | ||||
LayerState& refLayerState; | LayerState& refLayerState; | ||||
press() { layer = refLayerState.getActiveLayer(); | |||||
ptrsKeys[layer]->press(); } | |||||
press() { layerId = refLayerState.getActiveLayer(); | |||||
ptrsKeys[layerId]->press(); } | |||||
}; | }; | ||||
``` | ``` | ||||
Dependency diagram | Dependency diagram | ||||
``` | ``` | ||||
+------------+ | |||||
| Code_Layer | | |||||
+------------+ | |||||
| | |||||
|setActiveLayer() | |||||
| | |||||
v | |||||
+------------+ | |||||
| LayerState | | |||||
+------------+ | |||||
^ | |||||
| | |||||
|getActiveLayer() | |||||
| | |||||
+----------------------+ | |||||
| Key_LayeredKeys | | |||||
+----------------------+ | |||||
+------------+ | |||||
| Code_Layer | | |||||
+------------+ | |||||
| | |||||
|setActiveLayer() | |||||
| | |||||
v | |||||
+------------+ | |||||
| LayerState | | |||||
+------------+ | |||||
^ | |||||
| | |||||
|getActiveLayer() | |||||
| | |||||
+-----------------+ | |||||
| Key_LayeredKeys | | |||||
+-----------------+ | |||||
``` | ``` | ||||
Layer-scheme classes | Layer-scheme classes | ||||
-------------------- | -------------------- | ||||
Exercises | Exercises | ||||
--------- | --------- | ||||
1) Modify the keybrd_3_multi-layer.ino sketch to use two Code_LayerLock objects. | |||||
1) Modify the keybrd_3a_multi-layer.ino sketch to use two Code_LayerLock objects. | |||||
| Layout | **0** | **1** | | | Layout | **0** | **1** | | ||||
|:------:|:------:|:------:| | |:------:|:------:|:------:| |
* Code_ScS | * Code_ScS | ||||
* Code_ScNS | * Code_ScNS | ||||
The [keybrd_3_autoShift.ino](keybrd_3_autoShift/keybrd_3_autoShift.ino) sketch explains the AutoShift feature. | |||||
The [keybrd_3b_autoShift.ino](keybrd_3b_autoShift/keybrd_3b_autoShift.ino) sketch explains the AutoShift feature. | |||||
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md). | It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md). | ||||
After reading the sketch you too will be able to automatically shifted characters. | After reading the sketch you too will be able to automatically shifted characters. | ||||
Exercises | Exercises | ||||
--------- | --------- | ||||
1) Modify the keybrd_3_autoShift_annotated sketch to make a 3-layer keyboard with a default layer and two Code_LayerHold objects. | |||||
1) Modify the keybrd_3b_autoShift sketch to make a 3-layer keyboard with a default layer and two Code_LayerHold objects. | |||||
| Layout | **0** | **1** | | | Layout | **0** | **1** | | ||||
|:------:|:-----:|:-----:| | |:------:|:-----:|:-----:| |