diff --git a/README.md b/README.md index 3917e5e..12eb66c 100644 --- a/README.md +++ b/README.md @@ -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)
[mainSketch.ino](https://github.com/wolfv6/keybrd_DH/blob/master/examples/keybrd_DH/mainSketch.cpp)
diff --git a/src/Code_Null.h b/src/Code_Null.h index 903355c..5ab74b1 100644 --- a/src/Code_Null.h +++ b/src/Code_Null.h @@ -3,7 +3,7 @@ #include #include -/* 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 { diff --git a/src/objects_scancode.h b/src/objects_scancode.h index ff2dd3d..f80481e 100644 --- a/src/objects_scancode.h +++ b/src/objects_scancode.h @@ -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 diff --git a/tutorials/keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino b/tutorials/keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino index f945a7d..8dad50a 100644 --- a/tutorials/keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino +++ b/tutorials/keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino @@ -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* const ptrsCodes_00[] = { &s_a, &s_minus }; +Key_LayeredKeys k_00(ptrsCodes_00); + +Key* const ptrsCodes_01[] = { &s_b, &s_equal }; Key_LayeredKeys k_01(ptrsCodes_01); -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 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); diff --git a/tutorials/keybrd_3b_multi-layerLock/keybrd_3b_multi-layerLock.ino b/tutorials/keybrd_3b_multi-layerLock/keybrd_3b_multi-layerLock.ino index 1a11c19..48b96f7 100644 --- a/tutorials/keybrd_3b_multi-layerLock/keybrd_3b_multi-layerLock.ino +++ b/tutorials/keybrd_3b_multi-layerLock/keybrd_3b_multi-layerLock.ino @@ -6,29 +6,21 @@ This sketch: | Layout | **0** | **1** | |:------:|:-----:|:-----:| -| **0** | a [ | b ] | -| **1** |normal | sym | +| **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 +Pressing the "Normal" layer key locks the Normal layer. +Letters 'a' 'b' are on the Normal layer. -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. +Pressing the "Sym" layer key locks the Sym layer. +Symbols '-' '=' are on the Sym layer. */ // ################## GLOBAL ################### // ================= INCLUDES ================== //Keys #include -//#include -//#include #include #include -#include #include //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); diff --git a/tutorials/keybrd_3c_sublayerNull/keybrd_3c_sublayerNull.ino b/tutorials/keybrd_3c_sublayerNull/keybrd_3c_sublayerNull.ino index 1d2ce1f..e3de03c 100644 --- a/tutorials/keybrd_3c_sublayerNull/keybrd_3c_sublayerNull.ino +++ b/tutorials/keybrd_3c_sublayerNull/keybrd_3c_sublayerNull.ino @@ -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); diff --git a/tutorials/keybrd_3d_sublayerNestedKeys/keybrd_3d_sublayerNestedKeys.ino b/tutorials/keybrd_3d_sublayerNestedKeys/keybrd_3d_sublayerNestedKeys.ino index 7d16c91..167c3ed 100644 --- a/tutorials/keybrd_3d_sublayerNestedKeys/keybrd_3d_sublayerNestedKeys.ino +++ b/tutorials/keybrd_3d_sublayerNestedKeys/keybrd_3d_sublayerNestedKeys.ino @@ -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 -#include #include #include #include @@ -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); diff --git a/tutorials/keybrd_3e_sublayerNestedScSc/keybrd_3e_sublayerNestedScSc.ino b/tutorials/keybrd_3e_sublayerNestedScSc/keybrd_3e_sublayerNestedScSc.ino index c88f14f..6be426a 100644 --- a/tutorials/keybrd_3e_sublayerNestedScSc/keybrd_3e_sublayerNestedScSc.ino +++ b/tutorials/keybrd_3e_sublayerNestedScSc/keybrd_3e_sublayerNestedScSc.ino @@ -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 -#include #include #include #include @@ -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); diff --git a/tutorials/tutorial_3a_multi-layer_keyboard.md b/tutorials/tutorial_3ab_multi-layer_keyboard.md similarity index 84% rename from tutorials/tutorial_3a_multi-layer_keyboard.md rename to tutorials/tutorial_3ab_multi-layer_keyboard.md index c2381e4..010b295 100644 --- a/tutorials/tutorial_3a_multi-layer_keyboard.md +++ b/tutorials/tutorial_3ab_multi-layer_keyboard.md @@ -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.
Creative Commons License
keybrd tutorial by Wolfram Volpi is licensed under a Creative Commons Attribution 4.0 International License.
Permissions beyond the scope of this license may be available at https://github.com/wolfv6/keybrd/issues/new. diff --git a/tutorials/tutorial_3cde_sublayer_keyboard.md b/tutorials/tutorial_3cde_sublayer_keyboard.md new file mode 100644 index 0000000..d99d966 --- /dev/null +++ b/tutorials/tutorial_3cde_sublayer_keyboard.md @@ -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 +--------- + diff --git a/tutorials/tutorial_3b_autoShift.md b/tutorials/tutorial_3f_autoShift.md similarity index 100% rename from tutorials/tutorial_3b_autoShift.md rename to tutorials/tutorial_3f_autoShift.md