@@ -2,10 +2,10 @@ | |||
void Code_LayerHold::press() | |||
{ | |||
refLayerState.hold(layer); | |||
refLayerState.hold(layerId); | |||
} | |||
void Code_LayerHold::release() | |||
{ | |||
refLayerState.unhold(layer); | |||
refLayerState.unhold(layerId); | |||
} |
@@ -10,11 +10,11 @@ | |||
class Code_LayerHold : public Code | |||
{ | |||
private: | |||
const uint8_t layer; | |||
const uint8_t layerId; | |||
LayerState& refLayerState; | |||
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 release(); | |||
}; |
@@ -2,7 +2,7 @@ | |||
void Code_LayerLock::press() | |||
{ | |||
refLayerState.lock(layer); | |||
refLayerState.lock(layerId); | |||
} | |||
void Code_LayerLock::release() |
@@ -10,11 +10,11 @@ | |||
class Code_LayerLock : public Code | |||
{ | |||
private: | |||
const uint8_t layer; | |||
const uint8_t layerId; | |||
LayerState& refLayerState; | |||
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 release(); | |||
}; |
@@ -2,6 +2,6 @@ | |||
void Key_LayeredCodeSc::press() | |||
{ | |||
layer = refLayerState.getActiveLayer(); | |||
layerId = refLayerState.getActiveLayer(); | |||
pressCode(); | |||
} |
@@ -8,7 +8,7 @@ | |||
/* Class Key_LayeredCodeSc is a 2-layer code, 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, | |||
When the key is pressed, the active layerId is retrieved from refLayerState, | |||
and the object for the active layer is sent to USB. | |||
*/ | |||
class Key_LayeredCodeSc : public Key_LayeredCodeScBase |
@@ -2,7 +2,7 @@ | |||
void Key_LayeredCodeScBase::pressCode() | |||
{ | |||
if (layer) | |||
if (layerId) | |||
{ | |||
Keyboard.press(scancode1); | |||
} | |||
@@ -14,7 +14,7 @@ void Key_LayeredCodeScBase::pressCode() | |||
void Key_LayeredCodeScBase::release() | |||
{ | |||
if (layer) | |||
if (layerId) | |||
{ | |||
Keyboard.release(scancode1); | |||
} |
@@ -4,11 +4,9 @@ | |||
#include <inttypes.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 | |||
{ | |||
@@ -16,10 +14,10 @@ class Key_LayeredCodeScBase : public Code | |||
Code& refCode0; | |||
const uint16_t scancode1; | |||
protected: | |||
bool layer; | |||
bool layerId; //active layer when key was pressed, 0 or 1 | |||
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 release(); | |||
virtual void pressCode(); |
@@ -2,12 +2,12 @@ | |||
void Key_LayeredKeys::press() | |||
{ | |||
layer = refLayerState.getActiveLayer(); | |||
layerId = refLayerState.getActiveLayer(); | |||
ptrsKeys[layer]->press(); | |||
ptrsKeys[layerId]->press(); | |||
} | |||
void Key_LayeredKeys::release() | |||
{ | |||
ptrsKeys[layer]->release(); | |||
ptrsKeys[layerId]->release(); | |||
} |
@@ -8,14 +8,14 @@ | |||
/* 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. | |||
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 | |||
{ | |||
private: | |||
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; | |||
public: | |||
Key_LayeredKeys(Key* const ptrsKeys[]): ptrsKeys(ptrsKeys) {} |
@@ -2,6 +2,6 @@ | |||
void Key_LayeredScSc::press() | |||
{ | |||
layer = refLayerState.getActiveLayer(); | |||
layerId = refLayerState.getActiveLayer(); | |||
pressScancode(); | |||
} |
@@ -6,9 +6,9 @@ | |||
#include <Key_LayeredScScBase.h> | |||
/* 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 | |||
{ |
@@ -2,7 +2,7 @@ | |||
void Key_LayeredScScBase::pressScancode() | |||
{ | |||
if (layer) | |||
if (layerId) | |||
{ | |||
scancode = scancode1; | |||
} |
@@ -4,9 +4,9 @@ | |||
#include <inttypes.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 | |||
{ | |||
@@ -15,10 +15,10 @@ class Key_LayeredScScBase : public Code | |||
const uint16_t scancode1; | |||
uint16_t scancode; | |||
protected: | |||
bool layer; //0 or 1 | |||
bool layerId; //active layer when key was pressed, 0 or 1 | |||
public: | |||
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 release(); | |||
void pressScancode(); |
@@ -1,29 +1,29 @@ | |||
#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); | |||
} | |||
} | |||
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 | |||
*/ | |||
void LayerState::setActiveLayer(const uint8_t layer) | |||
void LayerState::setActiveLayer(const uint8_t layerId) | |||
{ | |||
activeLayer = layer; | |||
activeLayer = layerId; | |||
} | |||
uint8_t LayerState::getActiveLayer() |
@@ -13,12 +13,12 @@ class LayerState : public LayerStateInterface | |||
protected: | |||
uint8_t activeLayer; //currently active layer | |||
uint8_t lockedLayer; //most recently pressed lock layer | |||
virtual void setActiveLayer(const uint8_t layer); | |||
virtual void setActiveLayer(const uint8_t layerId); | |||
public: | |||
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(); | |||
}; | |||
#endif |
@@ -5,9 +5,9 @@ void LayerState_LED::begin() | |||
ptrsLEDs[getActiveLayer()]->on(); | |||
} | |||
void LayerState_LED::setActiveLayer(const uint8_t layer) | |||
void LayerState_LED::setActiveLayer(const uint8_t layerId) | |||
{ | |||
ptrsLEDs[activeLayer]->off(); | |||
activeLayer = layer; | |||
activeLayer = layerId; | |||
ptrsLEDs[activeLayer]->on(); | |||
} |
@@ -12,8 +12,8 @@ begin() should be called once to turn on LED for initial active layer. | |||
class LayerState_LED : public LayerState | |||
{ | |||
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: | |||
LayerState_LED(LED*const ptrsLEDs[]): ptrsLEDs(ptrsLEDs) {} | |||
void begin(); |
@@ -1,4 +1,4 @@ | |||
/* keybrd_3_multi-layer_annotated.ino | |||
/* keybrd_3a_multi-layerHold.ino | |||
This sketch: | |||
is firmware for a simple 2-layer keyboard | |||
@@ -40,7 +40,7 @@ Scanner_uC scanner(LOW, readPins, readPinCount); | |||
The CODES section instantiates six codes, one for each item in the layout. | |||
*/ | |||
/* ---------------- LAYER CODE ----------------- | |||
enum assigns id numbers to the layers. | |||
enum assigns layerId numbers to the layers. | |||
*/ | |||
enum layers { NORMAL, FN }; | |||
@@ -49,9 +49,9 @@ enum layers { NORMAL, FN }; | |||
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: | |||
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 | |||
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. | |||
@@ -78,7 +78,7 @@ Key* const ptrsCodes_11[] = { &s_b, &s_2 }; | |||
Key_LayeredKeys k_11(ptrsCodes_11); | |||
/* 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; | |||
@@ -0,0 +1,129 @@ | |||
/* 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(); | |||
} |
@@ -0,0 +1,135 @@ | |||
/* 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(); | |||
} |
@@ -0,0 +1,142 @@ | |||
/* 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(); | |||
} |
@@ -1,4 +1,4 @@ | |||
/* keybrd_3_autoShift_annotated.ino | |||
/* keybrd_3b_autoShift.ino | |||
This sketch: | |||
is a simple 2-layer keyboard with AutoShift | |||
@@ -25,19 +25,18 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore | |||
#include <Key_LayeredKeys.h> | |||
//Matrix | |||
#include <Row_uC.h> | |||
#include <Row.h> | |||
#include <Scanner_uC.h> | |||
#include <ScanDelay.h> | |||
// ============ SPEED CONFIGURATION ============ | |||
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 READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||
Scanner_uC scanner(LOW, readPins, readPinCount); | |||
// =================== CODES =================== | |||
// ---------------- LAYER CODE ----------------- | |||
@@ -101,10 +100,14 @@ LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
// =================== ROWS ==================== | |||
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 }; | |||
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 #################### | |||
void setup() |
@@ -1,7 +1,7 @@ | |||
Tutorial 2 - single-layer keyboard | |||
======================================= | |||
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) | |||
After reading the sketch you will be able to modify it to suite your own single-layer keyboard design. |
@@ -35,61 +35,60 @@ Pseudo code for simple layer scheme | |||
The following pseudo code is of three keybrd library classes. | |||
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. | |||
``` | |||
class Code_Layer | |||
{ | |||
int layer; | |||
int layerId; | |||
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. | |||
``` | |||
class LayerState | |||
{ | |||
int activeLayer; | |||
setActiveLayer(int layer) { activeLayer = layer; } | |||
setActiveLayer(int layerId) { activeLayer = layerId; } | |||
getActiveLayer() { return activeLayer; } | |||
}; | |||
``` | |||
**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 | |||
{ | |||
Key** ptrsKeys; //array of Key pointers, one Key pointer per layer | |||
LayerState& refLayerState; | |||
press() { layer = refLayerState.getActiveLayer(); | |||
ptrsKeys[layer]->press(); } | |||
press() { layerId = refLayerState.getActiveLayer(); | |||
ptrsKeys[layerId]->press(); } | |||
}; | |||
``` | |||
Dependency diagram | |||
``` | |||
+------------+ | |||
| Code_Layer | | |||
+------------+ | |||
| | |||
|setActiveLayer() | |||
| | |||
v | |||
+------------+ | |||
| LayerState | | |||
+------------+ | |||
^ | |||
| | |||
|getActiveLayer() | |||
| | |||
+----------------------+ | |||
| Key_LayeredKeys | | |||
+----------------------+ | |||
+------------+ | |||
| Code_Layer | | |||
+------------+ | |||
| | |||
|setActiveLayer() | |||
| | |||
v | |||
+------------+ | |||
| LayerState | | |||
+------------+ | |||
^ | |||
| | |||
|getActiveLayer() | |||
| | |||
+-----------------+ | |||
| Key_LayeredKeys | | |||
+-----------------+ | |||
``` | |||
Layer-scheme classes | |||
-------------------- | |||
@@ -124,7 +123,7 @@ Example single-layer Code classes include: | |||
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** | | |||
|:------:|:------:|:------:| |
@@ -10,7 +10,7 @@ Two keybrd classes use AutoShift: | |||
* Code_ScS | |||
* 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). | |||
After reading the sketch you too will be able to automatically shifted characters. | |||
@@ -18,7 +18,7 @@ After reading the sketch you too will be able to automatically shifted character | |||
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** | | |||
|:------:|:-----:|:-----:| |