@@ -36,7 +36,7 @@ Example complex keybrd sketch | |||
----------------------------- | |||
keybrd_DH and its instantiation files contain about 800 lines of code. | |||
It emulates the DataHand keyboard. | |||
The layout has 52 keys, 4 layers, 6 sub-layers, 2 matrices, 8 LEDs, and blinking LEDs. | |||
Its layout has 52 keys, 3 primary layers, 5 sub-layers, 2 matrices, 8 LEDs, and blinking LEDs. | |||
[keybrd_DH_library_developer_guide.md](https://github.com/wolfv6/keybrd_DH/blob/master/doc/keybrd_DH_library_developer_guide.md)<br> | |||
[mainSketch.ino](https://github.com/wolfv6/keybrd_DH/blob/master/examples/keybrd_DH/mainSketch.cpp)<br> |
@@ -3,7 +3,7 @@ | |||
#include <Arduino.h> | |||
#include <Code.h> | |||
/* Class Code_Null doesn't do anything. It is usefull for blank codes. | |||
/* Class Code_Null doesn't do anything. It is useful for blank codes. | |||
*/ | |||
class Code_Null: public Code | |||
{ |
@@ -176,4 +176,4 @@ Code_ScS s_greaterThan(KEY_PERIOD); | |||
Code_ScS s_question(KEY_SLASH); | |||
// ********** MISC CODES ********* | |||
Code_Null code_null; //usefull for blank keys | |||
Code_Null code_null; //useful for blank keys |
@@ -6,13 +6,14 @@ This sketch: | |||
| Layout | **0** | **1** | | |||
|:------:|-------|-------| | |||
| **0** | shift | a 1 | | |||
| **1** | fn | b 2 | | |||
| **0** | a - | b = | | |||
| **1** | fn | shift | | |||
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. | |||
The keys in column 1 have two characters each, one character for each layer. | |||
"fn" is a layer key. Holding the fn key down makes it the active layer. | |||
Releasing the fn key restores the normal layer. | |||
Letters 'a' and 'b' are on the normal layer. Symbols '-' and '=' are on the fn layer. | |||
*/ | |||
// ################## GLOBAL ################### | |||
// ================= INCLUDES ================== | |||
@@ -36,33 +37,33 @@ 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. | |||
*/ | |||
// =================== CODES =================== | |||
/* ---------------- LAYER CODE ----------------- | |||
enum assigns layerId numbers to the layers. | |||
NORMAL=0 and FN=1. LayerState's default layerId is 0. | |||
*/ | |||
enum layers { NORMAL, FN }; | |||
/* layerState keeps track of the active layer. | |||
/* | |||
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 | |||
1) the layerId that will be the active layer 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. | |||
When l_fn is pressed, it tells layerState to change the active layer to FN. | |||
When l_fn is released, it tells layerState that layer FN is released, | |||
and layerState restores the active layer to NORMAL (sets active layer to the default layerId 0). | |||
*/ | |||
Code_LayerHold l_fn(FN, layerState); | |||
// ---------------- SCAN CODES ----------------- | |||
Code_Sc s_a(KEY_A); | |||
Code_Sc s_b(KEY_B); | |||
Code_Sc s_1(KEY_1); | |||
Code_Sc s_2(KEY_2); | |||
Code_Sc s_minus(KEY_MINUS); | |||
Code_Sc s_equal(KEY_EQUAL); | |||
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); | |||
/* =================== KEYS ==================== | |||
@@ -71,14 +72,14 @@ The Key_LayeredKeys constructor takes one array of Code pointers - one Code obje | |||
The Key object names in this sketch start with a "k_" followed by row-column coordinates. | |||
*/ | |||
Key* const ptrsCodes_01[] = { &s_a, &s_1 }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
Key* const ptrsCodes_00[] = { &s_a, &s_minus }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
Key* const ptrsCodes_11[] = { &s_b, &s_2 }; | |||
Key_LayeredKeys k_11(ptrsCodes_11); | |||
Key* const ptrsCodes_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
/* Key_LayeredKeys has a reference to layerState. | |||
Thus Key_LayeredKeys can call layerState to get the active layerId. | |||
/* | |||
Key_LayeredKeys has a reference to layerState. | |||
*/ | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
@@ -91,15 +92,17 @@ The Code object then sends its scancode over USB. | |||
/* =================== ROWS ==================== | |||
Here we pack Key pointers into row objects. | |||
Rows are composed of a Key-pointer array. | |||
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. | |||
Thus rows can contain a mix of codes and multi-layered keys (subtype polymorphism). | |||
In this example, Key-pointer arrays contain both Code pointers (&s_shift and &l_fn) | |||
and Key pointers (&k_01 and &k_11). | |||
*/ | |||
Key* const ptrsKeys_0[] = { &s_shift, &k_01 }; | |||
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_fn, &k_11 }; | |||
Key* const ptrsKeys_1[] = { &l_fn, &s_shift }; | |||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1); | |||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1); | |||
@@ -6,29 +6,21 @@ This sketch: | |||
| 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. | |||
| **0** | a - | b = | | |||
| **1** |Normal | Sym | | |||
Pressing the "Normal" layer key locks the Normal layer. | |||
Letters 'a' 'b' are on the Normal layer. | |||
Pressing the "Sym" layer key locks the Sym layer. | |||
Symbols '-' '=' are on the Sym 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 | |||
@@ -45,25 +37,18 @@ 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. | |||
*/ | |||
// =================== CODES =================== | |||
// ---------------- LAYER CODE ----------------- | |||
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 | |||
The Code_LayerLock constructor has two parameters: | |||
1) the layerId that becomes the active layer when the key is pressed | |||
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. | |||
When l_normal is pressed, NORMAL becomes the active layer. | |||
When l_sym is pressed, SYM becomes the active layer. | |||
*/ | |||
Code_LayerLock l_normal(NORMAL, layerState); | |||
Code_LayerLock l_sym(SYM, layerState); | |||
@@ -71,42 +56,19 @@ Code_LayerLock l_sym(SYM, layerState); | |||
// ---------------- SCAN CODES ----------------- | |||
Code_Sc s_a(KEY_A); | |||
Code_Sc s_b(KEY_B); | |||
Code_Sc s_minus(KEY_MINUS); | |||
Code_Sc s_equal(KEY_EQUAL); | |||
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 }; | |||
// =================== KEYS ==================== | |||
Key* const ptrsCodes_00[] = { &s_a, &s_minus }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
Key* const ptrsCodes_01[] = { &s_b, &s_rightBracket }; | |||
Key* const ptrsCodes_01[] = { &s_b, &s_equal }; | |||
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. | |||
*/ | |||
// =================== ROWS ==================== | |||
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); |
@@ -1,24 +1,14 @@ | |||
/* 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 | |||
is firmware for layout with 2 layers plus 1 sublayer. | |||
runs on the first three 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 ================== | |||
@@ -44,30 +34,20 @@ 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. | |||
*/ | |||
// =================== CODES =================== | |||
/* ---------------- LAYER CODE ----------------- | |||
enum assigns layerId numbers to the layers. | |||
One LayerState object manages all 3 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); | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
// ---------------- SCAN CODES ----------------- | |||
Code_Sc s_a(KEY_A); | |||
Code_Sc s_b(KEY_B); | |||
@@ -81,38 +61,31 @@ 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. | |||
When a Key_LayeredKeys is pressed, layerState returns the active layerId, | |||
which could be any of the layerIds in l_normal, l_sym, l_num. | |||
The Key object names in this sketch start with a "k_" followed by row-column coordinates. | |||
The layout has one key with 3 layers, and two keys with 2 layers. | |||
But the layer scheme has 3 layers for all three keys. | |||
The extra layers are filled with duplicate codes and null codes. | |||
*/ | |||
Key* const ptrsCodes_00[] = { &s_a, &s_minus, &s_1 }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
/* | |||
s_equal is duplicated in layer 2. | |||
*/ | |||
Key* const ptrsCodes_01[] = { &s_b, &s_equal, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
/* | |||
code_null occupies layer 2. Class Code_Null doesn't do anything. It is useful for blank codes. | |||
Remember to fill all layers with codes. | |||
If the code_null were omitted from the array, dereferencing ptrsCodes_02[2] could cause a crash. | |||
*/ | |||
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. | |||
*/ | |||
// =================== ROWS ==================== | |||
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); |
@@ -1,30 +1,19 @@ | |||
/* 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 | |||
is firmware for layout with 2 layers plus 1 sublayer. | |||
runs on the first three 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> | |||
@@ -45,37 +34,35 @@ 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. | |||
*/ | |||
// =================== CODES =================== | |||
// ----------------- LAYER CODE ---------------- | |||
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 | |||
/* | |||
Key_LayeredKeys are associated with layerState. | |||
*/ | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
/* ---------------- SUBLAYER CODE -------------- | |||
Sublayers are implemented just like main layers. | |||
Here the Num sublayer is given it's own proper LayerState. | |||
*/ | |||
enum subLayers { SUBSYM, SUBNUM }; | |||
LayerState sublayerState; | |||
Code_LayerHold l_num(SUBNUM, sublayerState); | |||
/* | |||
Key_LayeredKeys1 are associated with sublayerState. | |||
Key_LayeredKeys (in layer) and Key_LayeredKeys1 (in sublayer) classes are nearly identical, | |||
only the static refLayerState are different. | |||
*/ | |||
LayerStateInterface& Key_LayeredKeys1::refLayerState = sublayerState; | |||
// ---------------- SCAN CODES ----------------- | |||
@@ -88,18 +75,20 @@ 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. | |||
The key k_sub00 contains codes for layerIds SUBSYM and SUBNUM. | |||
(The Num sublayer only has one key because small example. Usually sublayers have multiple keys.) | |||
*/ | |||
Key* const ptrsCodes_sub00[] = { &s_minus, &s_1 }; | |||
Key_LayeredKeys1 k_sub00(ptrsCodes_sub00); | |||
/* | |||
k_sub00 is nested in k_00. | |||
The key k_00 contains code and key for layerIds NORMAL and SYS. | |||
Notice that k_sub00 is of type Key_LayeredKeys1, while k_00 is of type Key_LayeredKeys. | |||
k_sub00 and k_00 are associated with distinct LayerStates. | |||
*/ | |||
Key* const ptrsCodes_00[] = { &s_a, &k_sub00 }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
@@ -109,19 +98,7 @@ 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. | |||
*/ | |||
// =================== ROWS ==================== | |||
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); |
@@ -1,30 +1,19 @@ | |||
/* keybrd_3d_sublayerNestedScSc.ino | |||
/* keybrd_3e_sublayerNestedScSc.ino | |||
This sketch: | |||
is firmware for a simple 2-layer keyboard | |||
runs on the first two rows and columns of a breadboard keyboard | |||
is firmware for layout 2 layers plus 1 sublayer. | |||
runs on the first three 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> | |||
@@ -45,31 +34,18 @@ 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. | |||
*/ | |||
// =================== CODES =================== | |||
// ---------------- LAYER CODE ----------------- | |||
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 | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
// ---------------- SUBLAYER CODE -------------- | |||
enum subLayers { SUBSYM, SUBNUM }; | |||
LayerState sublayerState; | |||
@@ -88,16 +64,20 @@ 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. | |||
The key k_sub00 contains codes for layerIds SUBSYM and SUBNUM. | |||
Key_LayeredScSc takes two scancode arguments. | |||
(The Num sublayer only has one key because small example. Usually sublayers have multiple keys.) | |||
*/ | |||
Key_LayeredScSc sub_00(KEY_MINUS, KEY_1); | |||
/* | |||
k_sub00 is nested in k_00. | |||
The key k_00 contains code and key for layerIds NORMAL and SYS. | |||
Notice that k_sub00 is of type Key_LayeredKeys1, while k_00 is of type Key_LayeredKeys. | |||
k_sub00 and k_00 are associated with distinct LayerStates. | |||
*/ | |||
Key* const ptrsCodes_00[] = { &s_a, &sub_00 }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
@@ -107,19 +87,7 @@ 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. | |||
*/ | |||
// =================== ROWS ==================== | |||
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); |
@@ -13,11 +13,27 @@ Multi-layer nomenclature | |||
**active layer** - is the layer currently used by the keyboard. | |||
**default layer** - is the active layer when the keyboard starts up (in class LayerState, default layerId=0). | |||
**layer scheme** - is a system for changing the active layer while typing (a single-layer scheme does not change layers). | |||
Code classes | |||
------------ | |||
Code objects only have one scancode or code. | |||
Example single-layer Code classes include: | |||
* Code_Sc (used in keybrd_2_single-layer.ino) | |||
* Code_ScS | |||
* Code_ScNS | |||
* Code_Shift | |||
* Code_LayerHold | |||
* Code_LayerLock | |||
Single-layer keybrd sketches have one Code object per key. | |||
Multi-layer keybrd sketches have multiple Code objects per key, one code for each layer. | |||
A simple multi-layer keybrd sketch | |||
---------------------------------- | |||
The [keybrd_3a_multi-layer.ino](keybrd_3a_multi-layer/keybrd_3a_multi-layer.ino) sketch is for a simple two-layer keyboard. | |||
The [keybrd_3a_multi-layerHold.ino](keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino) sketch is for a simple two-layer keyboard. | |||
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md). | |||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") | |||
@@ -107,28 +123,10 @@ Key_Layered classes include: | |||
* Key_LayeredScSc | |||
* Key_LayeredCodeSc | |||
The basic LayerState provided by the keybrd library is sufficient for implementing ordinary layer schemes. | |||
For experimental layer schemes, you would need to create a custom LayerState class, and possibly custom Code_Layer and Key_Layered classes as well. | |||
Single-layer Codes | |||
------------------ | |||
Most Code objects only have one scancode or code. | |||
Example single-layer Code classes include: | |||
* Code_Sc | |||
* Code_ScS | |||
* Code_ScNS | |||
* Code_Shift | |||
* Code_LayerHold | |||
* Code_LayerLock | |||
Exercises | |||
--------- | |||
1) Modify the keybrd_3a_multi-layer.ino sketch to use two Code_LayerLock objects. | |||
| Layout | **0** | **1** | | |||
|:------:|:------:|:------:| | |||
| **0** | a 1 | b 2 | | |||
| **1** | layer0 | layer1 | | |||
Compile and run keybrd_3a_multi-layerHold.ino and keybrd_3b_multi-layerLock.ino | |||
Notice how Code_LayerHold and Code_LayerLock objects behave. | |||
<br> | |||
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
@@ -0,0 +1,126 @@ | |||
Tutorial 3cde - sublayer keyboard | |||
================================= | |||
This tutorial assumes the reader understands the previous tutorial. | |||
When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch to write your very own multi-layer keyboard firmware. | |||
Sublayer nomenclature | |||
--------------------- | |||
**primary layer** - is a layer whose layer key is accessible from the default layer. | |||
**sublayer** - is a layer whose layer key is not accessible from the default layer. | |||
**layer group** - is a group of layers that occupy the same keys. | |||
Layer scheme with a sublayer | |||
---------------------------- | |||
This tutorial has 3 example sketches, all using this layout: | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = | c Num | | |||
| **1** |Normal | Sym | Enter | | |||
Each cell in the table's body represents a key. | |||
Bottom row keys have one layer. | |||
Top row keys have 2 or 3 layers. | |||
Pressing the "Normal" layer key locks the Normal layer. | |||
Letters 'a' 'b' 'c' are on the Normal layer. | |||
Pressing the "Sym" layer key locks the Sym layer. | |||
Symbols '-' '=' are on the Sym layer. | |||
The "Num" sublayer key is on the Sym layer. | |||
If the keyboard is locked on the Sym layer, holding Num down makes Num the active layer. | |||
Releasing the Num key restores the Sym layer. | |||
Number '1' is on the Num sublayer. | |||
todo [pic of 3 col bb kb] | |||
Three example 3 sketches implement the above layout using differently layer schemes. | |||
Keybrd provides flexibility todo?? | |||
Which layer scheme is best depends on the layout. | |||
3c - | |||
----------- | |||
keybrd_3c_sublayerNull.ino | |||
The layer scheme has one LayerState object cover all the layer groups. | |||
Duplicate codes and null codes fill the unused space. | |||
It's a bit of a kludge, but can be simple if there is little unused space. | |||
3d - | |||
----------- | |||
keybrd_3d_sublayerNestedKeys.ino | |||
The layer scheme has a distinct LayerState object for each layer group. | |||
One LayerState object per layer group is preferred because it models the logic of the layout. | |||
In this example, NORMAL+SYM is the primary layer group, which covers the top-row keys. | |||
layerState keeps track of the primary layer group's active layer. | |||
SUBSYM+SUBNUM is the sublayer group, which covers the top-left key. | |||
subLayerState keeps track of the sublayer group's active layer. | |||
The concepts of "sublayer" and "layer group" are independent. | |||
In the following layout for example, l_num and s_enter codes have swapped places. | |||
Num is now a primary layer, and SYM2+NUM2 is still layer group2. | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = | c Ent | | |||
| **1** |Normal | Sym | Num | | |||
3e - | |||
----------- | |||
keybrd_3e_sublayerNestedScSc.ino | |||
Key_LayeredKeys constructor takes any number of code arguments. | |||
Key_LayeredScSc is more specialized. It's constructor takes exactly two scancode arguments. | |||
No array was created for the two scancodes. | |||
This has advantages when a large sublayer group has two layers: | |||
* save SRAM | |||
* less clutter in sketch | |||
with custom layer classes, any layer scheme can be implemented | |||
DH is a complex layer scheme implemented with keybrd lib | |||
Complex layerschemes | |||
-------------------- | |||
The basic LayerState class used in the tutorials is sufficient for implementing many layer schemes. | |||
More complicated layer schemes would need custom LayerState classes, and possibly custom Code_Layer and Key_Layered classes as well. | |||
keybrd_DH is an example of a complex layer scheme (it emulates the DataHand keyboard). | |||
It's the most complex layer scheme I know of. | |||
The keybrd_DH project is a showcase of the keybrd library's capability. | |||
Don't let the complexity scare you; most layer schemes are much simpler. | |||
keybrd_DH's layout has 3 layers and 5 sub-layers. | |||
Most of the layer classes are custom classes, which reside in the keybrd_DH library. | |||
Layer classes used by keybrd_DH are listed below. | |||
The length of the list gives a hint of the layer scheme's complexity. | |||
DH Code_Layer classes include: | |||
* Code_LayerLock | |||
* Code_LayerLockMF_Protector | |||
* Code_LayerState_Toggle | |||
DH LayerState classes include: | |||
* LayerState | |||
* LayerState_DH | |||
* LayerState_NAS | |||
DH Key_Layered classes include: | |||
* Key_LayeredKeys | |||
* Key_LayeredScSc | |||
* Key_LayeredNav | |||
* Key_LayeredDoublePressToggle | |||
* Key_LayeredCodeSc_MF | |||
* Key_LayeredOperator | |||
* Key_LayeredNumber | |||
* Key_LayeredNumber_00 | |||
Exercises | |||
--------- | |||