keybrd Library Developer's Guide ================================ This guide if for maintaining and writing new classes for the keybrd library and its extension libraries. The most common reason for new classes are: * Port classes for micro controller or I/O expanders * custom layer schemes for multi-layer keyboards * experimental features ## Who this guide is for This guide is for the maintainers and developers of the keybrd library and it's extensions. It is assumed the reader is familiar with C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum. Debouncer and I/O expander use bit manipulation. ## Custom Row classes The keybrd library is flexible for designing custom Rows * RowBase functions can be overridden in a derived class * choice of Debouncers * choice of Scanners this example illustrates the custom Row classes for a fictional keybrd_Ext extension library the keybrd_Ext library is for a split keyboard with a matrix on each hand other custom Row classes would have a similar structure Row_Ext::keyWasPressed() overrides RowBase::keyWasPressed() Row_Ext::keyWasPressed() is used to unstick sticky keys Row_Ext_uC scans the primary matrix Row_Ext_ShiftRegisters scans the secondary matrix Row_Ext_uC and Row_Ext_ShiftRegisters are a custom classes composed of stock keybrd library classes Class inheritance diagram ``` RowBase | Row_Ext (override RowBase::keyWasPressed() ) / \ Row_Ext_uC Row_Ext_ShiftRegisters (inherit Row_Ext::keyWasPressed() ) RowScannerInterface / \ RowScanner_PinsArray RowScanner_SPIShiftRegisters ``` Dependency diagram ``` ________ Row_Ext_uC[1] _______________ / \ \ RowScanner_PinsArray[1] Debouncer_Samples[1] Key[1..*] / \ | strobePin[1] readPins[1..*] Code[1..*] _____ Row_Ext_ShiftRegisters[1] ___________ / \ \ RowScanner_SPIShiftRegisters[1] Debouncer_Samples[1] Key[1..*] / \ | strobePin[1] ROW_END[1] Code[1..*] ``` ## Class inheritance diagrams Keybrd library class inheritance diagram ``` _______ RowBase ________ / | \ Row_uC Row_ShiftRegisters Row_IOE _____ RowScannerInterface ______ / | \ RowScanner_PinsArray RowScanner_PinsBitwise RowScanner_SPIShiftRegisters IOExpanderPort RowPort | RowPort_PCA9655E (one RowPort class for each IOE type) ColPort | ColPort_PCA9655E (one ColPort class for each IOE type) ____ LED ____ / \ LED_PinNumber LED_PCA9655E DebouncerInterface | Debouncer_4Samples ScanDelay LayerStateInterface | LayerState Key __ | \ | Key_LayeredKeysArray | Code |_____________________ | \ \ | Code_LayerLock Code_LayerHold | |___________________________ | \ \ | Code_LayeredScScBase Code_LayeredCodeScBase | | | | Code_LayeredScSc Code_LayeredCodeSc | |__________________________________________ \ \ \ \ Code_Sc Code_Shift Code_AutoShift Code_LEDLock / | \ Code_ScS Code_ScNS Code_ScNS_00 ``` ## Dependency diagrams Example single-layer dependency diagram with LEDs ``` ___ Row_uC[1..*] ________ / \ \ RowScanner_PinsArray Debouncer Keys[1..*] __ | \ Code[1..*] Code_LEDLock[1..*] | LED_PinNumber[1] ``` Example multi-layer dependency diagram with layer LEDs ``` LayerStates[1..*] ________ Row_uC[1..*] _____________________/__ | \ / \ \ / \ | \ RowScanner_PinsArray[1] Debouncer[1] Keys[1..*] / Code_Layer[1..*] LED_PinNumber[0..*] | / Code[1..*] ``` Example secondary matrix with shift registers dependency diagram ``` Row_ShiftRegisters[1..*] / \ \ RowScanner_ShiftRegisters Debouncer Keys[1..*] | Code[1..*] ``` Example secondary matrix with I/O Expander dependency diagram with LEDs ``` ___ Row_IOE[1..*] _________ / \ \ RowScanner_PinsBitwise[1] Debouncer[1] Keys[1..*] __ / | \ | \ RowPort[1] RowPin[1] ColPort[1] Code[1..*] Code_LEDLock[1..*] \ / \ | \ / ColPins[1..*] LED[1] \ / IOExpanderPort[0..*] ``` ## Class naming conventions Class names start with upper case letter. Most derived-class names start with the base class name followed by "_" and a name e.g. ``` Code | Code_LayerLock ``` This convention leads to class names that convey information about the classes inheritance. Underscore delineates base class name and sub-class name. Capital letters delineate words. ## Layer-class naming conventions *Code_Layer* class names are concatenations of "Code_", "Layer" or layer name, and persistence. Example persistences are: * "Lock" - layer remains active after the layer key is released * "Hold" - layer is active for as long as layer key is held down Example Code_Layer class names: * Code_LayerHold * Code_LayerLock *LayerState* class names start with "LayerState" and end with a descriptive name. Example LayerState class names: * LayerState - basic LayerState class in keybrd library * LayerState_DH - main LayerState for the keybrd_DH library * LayerState_MF - LayerState for Mouse Function sub-layers in the keybrd_DH library *Code_Layered* class names start with "Code_Layered" and end with a descriptive name. Example Code_Layered class names: * Code_LayeredScSc * Key_LayeredKeysArray ## Style guide Following the style guide makes it easier for the next programmer to understand your code. * For class names, see above section "Class naming conventions" * For member names, use camelCase starting with lowercase letter. * Use constants rather than macros, except for header guards. * For constant names that could be macros, use ALL_CAPS_AND_UNDERSCORE. * **ITEM_COUNT** is a constant number of items. * **itemCount** is a variable number of items. * Use header guards CLASS_NAME_H. * Prefix pointer name with "ptr" e.g. ptrRow = &row; * Name arrays using the plural of element name e.g. Row* const = ptrsRows { &row0, &row1 }; * Pass arrays using array notation rather than pointer notation. Use ``` void printArray(char[] array); not void printArray( char* array); ``` * In constructor's initialization list, use same names for fields and constructor parameters. * Do not use new or malloc (making memory leaks impossible). * Document class interface in .h file, above the class declaration. * Code should be self-documenting. The only comments should be things that may need clarification. A simple function with a good name needs no comment. * Code is automatically formated before being pushed to the keybrd repository. The [astyle_cpp](astyle_cpp) file specifies the format: * Allman style indentation * indent 4 spaces * replace tabs with spaces * maximum code width of 100 columns ## Trace of keybrd scan Arduino does not have a debugger. So here is the next best thing; a list of functions in the order that they are called. The trace is of a single-layer keybrd scan (no LEDs and no I/O expander). Refer to it like a table of contents while reading the keybrd library. ``` loop() for each row RowBase::process() RowScanner_PinsArray::scan() strobe row on for each readPin set rowState bit strobe row off Debouncer_4Samples::debounce() debounce RowBase::pressRelease() for each key in row if falling edge Key_*::release() scanCode->release() Code_*::release() Keyboard.release(scancode) if rising edge Key_*::press() scanCode->press() Code_*::press() Keyboard.press(scancode) scanDelay.delay(); ``` ## The Arduino libraries The keybrd libraries compile on the Arduino IDE and make extensive use of the following [Arduino libraries](https://www.arduino.cc/en/Reference/Libraries): #include #include #include #include Creative Commons License
keybrd guide 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.