2014-04-06 18:49:27 +00:00
/* Copyright (C) 2014 by Jacob Alexander
*
2014-06-23 03:45:56 +00:00
* This file is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
2014-04-06 18:49:27 +00:00
*
2014-06-23 03:45:56 +00:00
* This file is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2014-04-06 18:49:27 +00:00
*
2014-06-23 03:45:56 +00:00
* You should have received a copy of the GNU General Public License
* along with this file . If not , see < http : //www.gnu.org/licenses/>.
2014-04-06 18:49:27 +00:00
*/
// ----- Includes -----
// Compiler Includes
# include <Lib/MacroLib.h>
// Project Includes
# include <cli.h>
# include <led.h>
# include <print.h>
# include <scan_loop.h>
// Keymaps
# include "usb_hid.h"
2014-09-14 22:51:36 +00:00
# include <generatedKeymap.h> // Generated using kll at compile time, in build directory
2014-04-06 18:49:27 +00:00
// Local Includes
# include "macro.h"
// ----- Function Declarations -----
2014-07-25 05:22:35 +00:00
void cliFunc_capList ( char * args ) ;
void cliFunc_capSelect ( char * args ) ;
2014-08-15 17:42:12 +00:00
void cliFunc_keyHold ( char * args ) ;
2014-07-25 05:22:35 +00:00
void cliFunc_keyPress ( char * args ) ;
void cliFunc_keyRelease ( char * args ) ;
void cliFunc_layerList ( char * args ) ;
2014-07-26 19:20:59 +00:00
void cliFunc_layerState ( char * args ) ;
2014-07-25 05:22:35 +00:00
void cliFunc_macroDebug ( char * args ) ;
void cliFunc_macroList ( char * args ) ;
void cliFunc_macroProc ( char * args ) ;
void cliFunc_macroShow ( char * args ) ;
void cliFunc_macroStep ( char * args ) ;
2014-04-06 18:49:27 +00:00
2014-08-05 18:33:55 +00:00
// ----- Enums -----
// Bit positions are important, passes (correct key) always trump incorrect key votes
typedef enum TriggerMacroVote {
2014-08-23 17:49:13 +00:00
TriggerMacroVote_Release = 0x10 , // Correct key
TriggerMacroVote_PassRelease = 0x18 , // Correct key (both pass and release)
TriggerMacroVote_Pass = 0x8 , // Correct key
TriggerMacroVote_DoNothingRelease = 0x4 , // Incorrect key
TriggerMacroVote_DoNothing = 0x2 , // Incorrect key
TriggerMacroVote_Fail = 0x1 , // Incorrect key
TriggerMacroVote_Invalid = 0x0 , // Invalid state
2014-08-05 18:33:55 +00:00
} TriggerMacroVote ;
typedef enum TriggerMacroEval {
TriggerMacroEval_DoNothing ,
TriggerMacroEval_DoResult ,
TriggerMacroEval_DoResultAndRemove ,
TriggerMacroEval_Remove ,
} TriggerMacroEval ;
2014-08-06 19:18:06 +00:00
typedef enum ResultMacroEval {
ResultMacroEval_DoNothing ,
ResultMacroEval_Remove ,
} ResultMacroEval ;
2014-08-05 18:33:55 +00:00
2014-04-06 18:49:27 +00:00
// ----- Variables -----
2014-04-13 04:13:37 +00:00
// Macro Module command dictionary
2014-08-15 17:42:12 +00:00
const char macroCLIDictName [ ] = " Macro Module Commands " ;
const CLIDictItem macroCLIDict [ ] = {
2014-04-06 18:49:27 +00:00
{ " capList " , " Prints an indexed list of all non USB keycode capabilities. " , cliFunc_capList } ,
2014-07-25 17:53:33 +00:00
{ " capSelect " , " Triggers the specified capabilities. First two args are state and stateType. " NL " \t \t \033 [35mK11 \033 [0m Keyboard Capability 0x0B " , cliFunc_capSelect } ,
2014-08-15 17:42:12 +00:00
{ " keyHold " , " Send key-hold events to the macro module. Duplicates have undefined behaviour. " NL " \t \t \033 [35mS10 \033 [0m Scancode 0x0A " , cliFunc_keyHold } ,
{ " keyPress " , " Send key-press events to the macro module. Duplicates have undefined behaviour. " NL " \t \t \033 [35mS10 \033 [0m Scancode 0x0A " , cliFunc_keyPress } ,
{ " keyRelease " , " Send key-release event to macro module. Duplicates have undefined behaviour. " NL " \t \t \033 [35mS10 \033 [0m Scancode 0x0A " , cliFunc_keyRelease } ,
2014-07-25 05:22:35 +00:00
{ " layerList " , " List available layers. " , cliFunc_layerList } ,
2014-07-26 19:20:59 +00:00
{ " layerState " , " Modify specified indexed layer state <layer> <state byte>. " NL " \t \t \033 [35mL2 \033 [0m Indexed Layer 0x02 " NL " \t \t 0 Off, 1 Shift, 2 Latch, 4 Lock States " , cliFunc_layerState } ,
2014-04-06 18:49:27 +00:00
{ " macroDebug " , " Disables/Enables sending USB keycodes to the Output Module and prints U/K codes. " , cliFunc_macroDebug } ,
2014-07-25 05:22:35 +00:00
{ " macroList " , " List the defined trigger and result macros. " , cliFunc_macroList } ,
{ " macroProc " , " Pause/Resume macro processing. " , cliFunc_macroProc } ,
2014-07-25 06:42:38 +00:00
{ " macroShow " , " Show the macro corresponding to the given index. " NL " \t \t \033 [35mT16 \033 [0m Indexed Trigger Macro 0x10, \033 [35mR12 \033 [0m Indexed Result Macro 0x0C " , cliFunc_macroShow } ,
2014-07-25 05:22:35 +00:00
{ " macroStep " , " Do N macro processing steps. Defaults to 1. " , cliFunc_macroStep } ,
2014-04-06 18:49:27 +00:00
{ 0 , 0 , 0 } // Null entry for dictionary end
} ;
2014-04-06 20:12:31 +00:00
// Macro debug flag - If set, clears the USB Buffers after signalling processing completion
uint8_t macroDebugMode = 0 ;
2014-07-25 05:22:35 +00:00
// Macro pause flag - If set, the macro module pauses processing, unless unset, or the step counter is non-zero
uint8_t macroPauseMode = 0 ;
// Macro step counter - If non-zero, the step counter counts down every time the macro module does one processing loop
2014-09-11 18:17:17 +00:00
uint16_t macroStepCounter = 0 ;
2014-07-25 05:22:35 +00:00
2014-06-23 03:45:56 +00:00
// Key Trigger List Buffer
2014-07-26 21:06:19 +00:00
TriggerGuide macroTriggerListBuffer [ MaxScanCode ] ;
2014-06-23 03:45:56 +00:00
uint8_t macroTriggerListBufferSize = 0 ;
2014-07-26 21:06:19 +00:00
// Pending Trigger Macro Index List
// * Any trigger macros that need processing from a previous macro processing loop
2014-06-23 03:45:56 +00:00
// TODO, figure out a good way to scale this array size without wasting too much memory, but not rejecting macros
// Possibly could be calculated by the KLL compiler
2014-07-25 05:22:35 +00:00
// XXX It may be possible to calculate the worst case using the KLL compiler
2014-09-11 18:17:17 +00:00
uint16_t macroTriggerMacroPendingList [ TriggerMacroNum ] = { 0 } ;
uint16_t macroTriggerMacroPendingListSize = 0 ;
2014-07-26 21:06:19 +00:00
// Layer Index Stack
// * When modifying layer state and the state is non-0x0, the stack must be adjusted
2014-09-11 18:17:17 +00:00
uint16_t macroLayerIndexStack [ LayerNum + 1 ] = { 0 } ;
uint16_t macroLayerIndexStackSize = 0 ;
2014-07-26 21:06:19 +00:00
// Pending Result Macro Index List
// * Any result macro that needs processing from a previous macro processing loop
2014-09-11 18:17:17 +00:00
uint16_t macroResultMacroPendingList [ ResultMacroNum ] = { 0 } ;
uint16_t macroResultMacroPendingListSize = 0 ;
2014-06-23 03:45:56 +00:00
2014-04-06 20:12:31 +00:00
2014-04-06 18:49:27 +00:00
2014-08-08 03:03:39 +00:00
// ----- Capabilities -----
2014-09-08 04:10:49 +00:00
// Sets the given layer with the specified layerState
void Macro_layerState ( uint8_t state , uint8_t stateType , uint16_t layer , uint8_t layerState )
2014-08-08 03:03:39 +00:00
{
// Is layer in the LayerIndexStack?
uint8_t inLayerIndexStack = 0 ;
2014-09-11 18:17:17 +00:00
uint16_t stackItem = 0 ;
2014-08-08 03:03:39 +00:00
while ( stackItem < macroLayerIndexStackSize )
{
// Flag if layer is already in the LayerIndexStack
if ( macroLayerIndexStack [ stackItem ] = = layer )
{
inLayerIndexStack = 1 ;
break ;
}
// Increment to next item
stackItem + + ;
}
// Toggle Layer State Byte
2014-09-17 00:04:59 +00:00
if ( LayerState [ layer ] & layerState )
2014-08-08 03:03:39 +00:00
{
// Unset
2014-09-17 00:04:59 +00:00
LayerState [ layer ] & = ~ layerState ;
2014-08-08 03:03:39 +00:00
}
else
{
// Set
2014-09-17 00:04:59 +00:00
LayerState [ layer ] | = layerState ;
2014-08-08 03:03:39 +00:00
}
// If the layer was not in the LayerIndexStack add it
if ( ! inLayerIndexStack )
{
macroLayerIndexStack [ macroLayerIndexStackSize + + ] = layer ;
}
// If the layer is in the LayerIndexStack and the state is 0x00, remove
2014-09-17 00:04:59 +00:00
if ( LayerState [ layer ] = = 0x00 & & inLayerIndexStack )
2014-08-08 03:03:39 +00:00
{
// Remove the layer from the LayerIndexStack
// Using the already positioned stackItem variable from the loop above
while ( stackItem < macroLayerIndexStackSize )
{
macroLayerIndexStack [ stackItem ] = macroLayerIndexStack [ stackItem + 1 ] ;
stackItem + + ;
}
// Reduce LayerIndexStack size
macroLayerIndexStackSize - - ;
}
}
2014-09-08 04:10:49 +00:00
// Modifies the specified Layer control byte
// Argument #1: Layer Index -> uint16_t
// Argument #2: Layer State -> uint8_t
void Macro_layerState_capability ( uint8_t state , uint8_t stateType , uint8_t * args )
{
// Display capability name
if ( stateType = = 0xFF & & state = = 0xFF )
{
print ( " Macro_layerState(layerIndex,layerState) " ) ;
return ;
}
2014-09-11 03:53:30 +00:00
// Only use capability on press or release
// TODO Analog
// XXX This may cause issues, might be better to implement state table here to decide -HaaTa
if ( stateType = = 0x00 & & state = = 0x02 ) // Hold condition
return ;
2014-09-08 04:10:49 +00:00
// Get layer index from arguments
2014-09-11 18:17:17 +00:00
// Cast pointer to uint8_t to uint16_t then access that memory location
2014-09-08 04:10:49 +00:00
uint16_t layer = * ( uint16_t * ) ( & args [ 0 ] ) ;
// Get layer toggle byte
uint8_t layerState = args [ sizeof ( uint16_t ) ] ;
Macro_layerState ( state , stateType , layer , layerState ) ;
}
// Latches given layer
// Argument #1: Layer Index -> uint16_t
void Macro_layerLatch_capability ( uint8_t state , uint8_t stateType , uint8_t * args )
{
// Display capability name
if ( stateType = = 0xFF & & state = = 0xFF )
{
print ( " Macro_layerLatch(layerIndex) " ) ;
return ;
}
2014-09-11 03:53:30 +00:00
// Only use capability on press
// TODO Analog
// XXX To make sense, this code be on press or release. Or it could even be a sticky shift (why? dunno) -HaaTa
if ( stateType = = 0x00 & & state ! = 0x01 ) // All normal key conditions except press
return ;
2014-09-08 04:10:49 +00:00
// Get layer index from arguments
2014-09-11 18:17:17 +00:00
// Cast pointer to uint8_t to uint16_t then access that memory location
2014-09-08 04:10:49 +00:00
uint16_t layer = * ( uint16_t * ) ( & args [ 0 ] ) ;
Macro_layerState ( state , stateType , layer , 0x02 ) ;
}
// Locks given layer
// Argument #1: Layer Index -> uint16_t
void Macro_layerLock_capability ( uint8_t state , uint8_t stateType , uint8_t * args )
{
// Display capability name
if ( stateType = = 0xFF & & state = = 0xFF )
{
print ( " Macro_layerLock(layerIndex) " ) ;
return ;
}
2014-09-11 03:53:30 +00:00
// Only use capability on press
// TODO Analog
// XXX Could also be on release, but that's sorta dumb -HaaTa
if ( stateType = = 0x00 & & state ! = 0x01 ) // All normal key conditions except press
return ;
2014-09-08 04:10:49 +00:00
// Get layer index from arguments
2014-09-11 18:17:17 +00:00
// Cast pointer to uint8_t to uint16_t then access that memory location
2014-09-08 04:10:49 +00:00
uint16_t layer = * ( uint16_t * ) ( & args [ 0 ] ) ;
Macro_layerState ( state , stateType , layer , 0x04 ) ;
}
// Shifts given layer
// Argument #1: Layer Index -> uint16_t
void Macro_layerShift_capability ( uint8_t state , uint8_t stateType , uint8_t * args )
{
// Display capability name
if ( stateType = = 0xFF & & state = = 0xFF )
{
print ( " Macro_layerShift(layerIndex) " ) ;
return ;
}
2014-09-11 03:53:30 +00:00
// Only use capability on press or release
// TODO Analog
if ( stateType = = 0x00 & & ( state = = 0x00 | | state = = 0x02 ) ) // Only pass press or release conditions
return ;
2014-09-08 04:10:49 +00:00
// Get layer index from arguments
2014-09-11 18:17:17 +00:00
// Cast pointer to uint8_t to uint16_t then access that memory location
2014-09-08 04:10:49 +00:00
uint16_t layer = * ( uint16_t * ) ( & args [ 0 ] ) ;
Macro_layerState ( state , stateType , layer , 0x01 ) ;
}
2014-08-08 03:03:39 +00:00
2014-04-06 18:49:27 +00:00
// ----- Functions -----
2014-06-23 03:45:56 +00:00
// Looks up the trigger list for the given scan code (from the active layer)
2014-07-26 21:06:19 +00:00
// NOTE: Calling function must handle the NULL pointer case
2014-09-11 17:54:50 +00:00
nat_ptr_t * Macro_layerLookup ( uint8_t scanCode )
2014-06-14 18:00:29 +00:00
{
2014-07-26 21:06:19 +00:00
// If no trigger macro is defined at the given layer, fallthrough to the next layer
2014-09-11 18:17:17 +00:00
for ( uint16_t layerIndex = 0 ; layerIndex < macroLayerIndexStackSize ; layerIndex + + )
2014-07-26 21:06:19 +00:00
{
2014-08-08 03:03:39 +00:00
// Lookup Layer
2014-09-17 00:04:59 +00:00
const Layer * layer = & LayerIndex [ macroLayerIndexStack [ layerIndex ] ] ;
2014-07-26 21:06:19 +00:00
2014-08-08 03:03:39 +00:00
// Check if latch has been pressed for this layer
// XXX Regardless of whether a key is found, the latch is removed on first lookup
2014-09-17 00:04:59 +00:00
uint8_t latch = LayerState [ layerIndex ] & 0x02 ;
2014-08-08 03:03:39 +00:00
if ( latch )
{
2014-09-17 00:04:59 +00:00
LayerState [ layerIndex ] & = ~ 0x02 ;
2014-08-08 03:03:39 +00:00
}
// Only use layer, if state is valid
// XOR each of the state bits
// If only two are enabled, do not use this state
2014-09-17 00:04:59 +00:00
if ( ( LayerState [ layerIndex ] & 0x01 ) ^ ( latch > > 1 ) ^ ( ( LayerState [ layerIndex ] & 0x04 ) > > 2 ) )
2014-08-08 03:03:39 +00:00
{
// Lookup layer
2014-09-11 17:54:50 +00:00
nat_ptr_t * * map = ( nat_ptr_t * * ) layer - > triggerMap ;
2014-08-08 03:03:39 +00:00
// Determine if layer has key defined
2014-09-17 00:04:59 +00:00
// Make sure scanCode is between layer first and last scancodes
if ( map ! = 0
& & scanCode < layer - > last
& & scanCode > layer - > first
& & * map [ scanCode - layer - > first ] ! = 0 )
{
return map [ scanCode - layer - > first ] ;
}
2014-08-08 03:03:39 +00:00
}
2014-07-26 21:06:19 +00:00
}
// Do lookup on default layer
2014-09-11 17:54:50 +00:00
nat_ptr_t * * map = ( nat_ptr_t * * ) LayerIndex [ 0 ] . triggerMap ;
2014-07-26 21:06:19 +00:00
2014-09-17 00:04:59 +00:00
// Lookup default layer
const Layer * layer = & LayerIndex [ macroLayerIndexStack [ 0 ] ] ;
// Make sure scanCode is between layer first and last scancodes
if ( map ! = 0
& & scanCode < layer - > last
& & scanCode > layer - > first
& & * map [ scanCode - layer - > first ] ! = 0 )
2014-07-26 21:06:19 +00:00
{
2014-09-17 00:04:59 +00:00
return map [ scanCode - layer - > first ] ;
2014-07-26 21:06:19 +00:00
}
2014-09-17 00:04:59 +00:00
// Otherwise no defined Trigger Macro
erro_msg ( " Scan Code has no defined Trigger Macro: " ) ;
printHex ( scanCode ) ;
return 0 ;
2014-06-14 18:00:29 +00:00
}
2014-06-23 03:45:56 +00:00
// Update the scancode key state
// States:
2014-07-26 21:06:19 +00:00
// * 0x00 - Off
2014-06-23 03:45:56 +00:00
// * 0x01 - Pressed
// * 0x02 - Held
// * 0x03 - Released
// * 0x04 - Unpressed (this is currently ignored)
inline void Macro_keyState ( uint8_t scanCode , uint8_t state )
2014-06-14 18:00:29 +00:00
{
2014-06-23 03:45:56 +00:00
// Only add to macro trigger list if one of three states
switch ( state )
{
case 0x01 : // Pressed
case 0x02 : // Held
case 0x03 : // Released
2014-07-26 21:06:19 +00:00
macroTriggerListBuffer [ macroTriggerListBufferSize ] . scanCode = scanCode ;
macroTriggerListBuffer [ macroTriggerListBufferSize ] . state = state ;
macroTriggerListBuffer [ macroTriggerListBufferSize ] . type = 0x00 ; // Normal key
macroTriggerListBufferSize + + ;
2014-06-23 03:45:56 +00:00
break ;
}
2014-06-14 18:00:29 +00:00
}
2014-06-23 03:45:56 +00:00
// Update the scancode analog state
// States:
2014-07-26 21:06:19 +00:00
// * 0x00 - Off
2014-06-23 03:45:56 +00:00
// * 0x01 - Released
// * 0x02-0xFF - Analog value (low to high)
inline void Macro_analogState ( uint8_t scanCode , uint8_t state )
{
2014-07-26 21:06:19 +00:00
// Only add to macro trigger list if non-off
if ( state ! = 0x00 )
{
macroTriggerListBuffer [ macroTriggerListBufferSize ] . scanCode = scanCode ;
macroTriggerListBuffer [ macroTriggerListBufferSize ] . state = state ;
macroTriggerListBuffer [ macroTriggerListBufferSize ] . type = 0x02 ; // Analog key
macroTriggerListBufferSize + + ;
}
2014-06-23 03:45:56 +00:00
}
2014-06-14 18:00:29 +00:00
2014-06-23 03:45:56 +00:00
// Update led state
// States:
2014-07-26 21:06:19 +00:00
// * 0x00 - Off
2014-06-23 03:45:56 +00:00
// * 0x01 - On
inline void Macro_ledState ( uint8_t ledCode , uint8_t state )
{
2014-07-26 21:06:19 +00:00
// Only add to macro trigger list if non-off
if ( state ! = 0x00 )
{
macroTriggerListBuffer [ macroTriggerListBufferSize ] . scanCode = ledCode ;
macroTriggerListBuffer [ macroTriggerListBufferSize ] . state = state ;
macroTriggerListBuffer [ macroTriggerListBufferSize ] . type = 0x01 ; // LED key
macroTriggerListBufferSize + + ;
}
2014-06-23 03:45:56 +00:00
}
2014-06-14 18:00:29 +00:00
2014-08-05 18:33:55 +00:00
// Append result macro to pending list, checking for duplicates
// Do nothing if duplicate
2014-08-20 17:53:22 +00:00
inline void Macro_appendResultMacroToPendingList ( TriggerMacro * triggerMacro )
2014-08-05 18:33:55 +00:00
{
2014-08-20 17:53:22 +00:00
// Lookup result macro index
2014-09-11 18:17:17 +00:00
var_uint_t resultMacroIndex = triggerMacro - > result ;
2014-08-20 17:53:22 +00:00
2014-08-05 18:33:55 +00:00
// Iterate through result macro pending list, making sure this macro hasn't been added yet
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 0 ; macro < macroResultMacroPendingListSize ; macro + + )
2014-08-05 18:33:55 +00:00
{
// If duplicate found, do nothing
if ( macroResultMacroPendingList [ macro ] = = resultMacroIndex )
return ;
}
// No duplicates found, add to pending list
macroResultMacroPendingList [ macroResultMacroPendingListSize + + ] = resultMacroIndex ;
2014-08-20 17:53:22 +00:00
// Lookup scanCode of the last key in the last combo
2014-09-11 18:17:17 +00:00
var_uint_t pos = 0 ;
2014-08-20 17:53:22 +00:00
for ( uint8_t comboLength = triggerMacro - > guide [ 0 ] ; comboLength > 0 ; )
{
pos + = TriggerGuideSize * comboLength + 1 ;
comboLength = triggerMacro - > guide [ pos ] ;
}
uint8_t scanCode = ( ( TriggerGuide * ) & triggerMacro - > guide [ pos - TriggerGuideSize ] ) - > scanCode ;
// Lookup scanCode in buffer list for the current state and stateType
for ( uint8_t keyIndex = 0 ; keyIndex < macroTriggerListBufferSize ; keyIndex + + )
{
if ( macroTriggerListBuffer [ keyIndex ] . scanCode = = scanCode )
{
ResultMacroList [ resultMacroIndex ] . state = macroTriggerListBuffer [ keyIndex ] . state ;
ResultMacroList [ resultMacroIndex ] . stateType = macroTriggerListBuffer [ keyIndex ] . type ;
}
}
// Reset the macro position
ResultMacroList [ resultMacroIndex ] . pos = 0 ;
2014-08-05 18:33:55 +00:00
}
// Determine if long ResultMacro (more than 1 seqence element)
inline uint8_t Macro_isLongResultMacro ( ResultMacro * macro )
2014-06-23 03:45:56 +00:00
{
2014-08-05 18:33:55 +00:00
// Check the second sequence combo length
2014-08-20 17:53:22 +00:00
// If non-zero return non-zero (long sequence)
2014-08-05 18:33:55 +00:00
// 0 otherwise (short sequence)
2014-09-11 18:17:17 +00:00
var_uint_t position = 1 ;
for ( var_uint_t result = 0 ; result < macro - > guide [ 0 ] ; result + + )
2014-08-20 17:53:22 +00:00
position + = ResultGuideSize ( ( ResultGuide * ) & macro - > guide [ position ] ) ;
return macro - > guide [ position ] ;
2014-08-05 18:33:55 +00:00
}
2014-06-14 18:00:29 +00:00
2014-08-20 17:53:22 +00:00
// Determine if long TriggerMacro (more than 1 sequence element)
inline uint8_t Macro_isLongTriggerMacro ( TriggerMacro * macro )
{
// Check the second sequence combo length
// If non-zero return non-zero (long sequence)
// 0 otherwise (short sequence)
return macro - > guide [ macro - > guide [ 0 ] * TriggerGuideSize + 1 ] ;
}
// Votes on the given key vs. guide, short macros
inline TriggerMacroVote Macro_evalShortTriggerMacroVote ( TriggerGuide * key , TriggerGuide * guide )
{
// Depending on key type
switch ( guide - > type )
{
// Normal State Type
case 0x00 :
// For short TriggerMacros completely ignore incorrect keys
if ( guide - > scanCode = = key - > scanCode )
{
switch ( key - > state )
{
// Correct key, pressed, possible passing
case 0x01 :
return TriggerMacroVote_Pass ;
// Correct key, held, possible passing or release
case 0x02 :
return TriggerMacroVote_PassRelease ;
// Correct key, released, possible release
case 0x03 :
return TriggerMacroVote_Release ;
}
}
return TriggerMacroVote_DoNothing ;
// LED State Type
case 0x01 :
erro_print ( " LED State Type - Not implemented... " ) ;
break ;
// Analog State Type
case 0x02 :
erro_print ( " Analog State Type - Not implemented... " ) ;
break ;
// Invalid State Type
default :
erro_print ( " Invalid State Type. This is a bug. " ) ;
break ;
}
// XXX Shouldn't reach here
return TriggerMacroVote_Invalid ;
}
// Votes on the given key vs. guide, long macros
// A long macro is defined as a guide with more than 1 combo
inline TriggerMacroVote Macro_evalLongTriggerMacroVote ( TriggerGuide * key , TriggerGuide * guide )
2014-08-05 18:33:55 +00:00
{
// Depending on key type
switch ( guide - > type )
2014-06-23 03:45:56 +00:00
{
2014-08-05 18:33:55 +00:00
// Normal State Type
case 0x00 :
// Depending on the state of the buffered key, make voting decision
// Incorrect key
if ( guide - > scanCode ! = key - > scanCode )
2014-06-23 03:45:56 +00:00
{
2014-08-05 18:33:55 +00:00
switch ( key - > state )
{
// Wrong key, pressed, fail
case 0x01 :
return TriggerMacroVote_Fail ;
2014-08-23 17:49:13 +00:00
// Wrong key, held, do not pass (no effect)
2014-08-05 18:33:55 +00:00
case 0x02 :
return TriggerMacroVote_DoNothing ;
2014-08-23 17:49:13 +00:00
// Wrong key released, fail out if pos == 0
case 0x03 :
return TriggerMacroVote_DoNothing | TriggerMacroVote_DoNothingRelease ;
2014-08-05 18:33:55 +00:00
}
}
2014-06-23 03:45:56 +00:00
2014-08-05 18:33:55 +00:00
// Correct key
else
{
switch ( key - > state )
2014-06-23 03:45:56 +00:00
{
2014-08-05 18:33:55 +00:00
// Correct key, pressed, possible passing
case 0x01 :
return TriggerMacroVote_Pass ;
// Correct key, held, possible passing or release
case 0x02 :
return TriggerMacroVote_PassRelease ;
// Correct key, released, possible release
case 0x03 :
return TriggerMacroVote_Release ;
2014-06-23 03:45:56 +00:00
}
2014-08-05 18:33:55 +00:00
}
break ;
// LED State Type
case 0x01 :
erro_print ( " LED State Type - Not implemented... " ) ;
break ;
// Analog State Type
case 0x02 :
erro_print ( " Analog State Type - Not implemented... " ) ;
break ;
// Invalid State Type
default :
erro_print ( " Invalid State Type. This is a bug. " ) ;
break ;
}
// XXX Shouldn't reach here
return TriggerMacroVote_Invalid ;
}
// Evaluate/Update TriggerMacro
2014-09-11 18:17:17 +00:00
inline TriggerMacroEval Macro_evalTriggerMacro ( var_uint_t triggerMacroIndex )
2014-08-05 18:33:55 +00:00
{
// Lookup TriggerMacro
TriggerMacro * macro = & TriggerMacroList [ triggerMacroIndex ] ;
// Check if macro has finished and should be incremented sequence elements
if ( macro - > state = = TriggerMacro_Release )
{
macro - > state = TriggerMacro_Waiting ;
2014-08-20 17:53:22 +00:00
macro - > pos = macro - > pos + macro - > guide [ macro - > pos ] * TriggerGuideSize + 1 ;
2014-08-05 18:33:55 +00:00
}
// Current Macro position
2014-09-11 18:17:17 +00:00
var_uint_t pos = macro - > pos ;
2014-08-05 18:33:55 +00:00
// Length of the combo being processed
2014-08-20 17:53:22 +00:00
uint8_t comboLength = macro - > guide [ pos ] * TriggerGuideSize ;
2014-08-05 18:33:55 +00:00
// If no combo items are left, remove the TriggerMacro from the pending list
if ( comboLength = = 0 )
{
return TriggerMacroEval_Remove ;
}
2014-08-20 17:53:22 +00:00
// Check if this is a long Trigger Macro
uint8_t longMacro = Macro_isLongTriggerMacro ( macro ) ;
// Iterate through the items in the combo, voting the on the key state
2014-08-05 18:33:55 +00:00
// If any of the pressed keys do not match, fail the macro
//
// The macro is waiting for input when in the TriggerMacro_Waiting state
// Once all keys have been pressed/held (only those keys), entered TriggerMacro_Press state (passing)
// Transition to the next combo (if it exists) when a single key is released (TriggerMacro_Release state)
// On scan after position increment, change to TriggerMacro_Waiting state
// TODO Add support for system LED states (NumLock, CapsLock, etc.)
// TODO Add support for analog key states
// TODO Add support for 0x00 Key state (not pressing a key, not all that useful in general)
// TODO Add support for Press/Hold/Release differentiation when evaluating (not sure if useful)
TriggerMacroVote overallVote = TriggerMacroVote_Invalid ;
2014-08-20 17:53:22 +00:00
for ( uint8_t comboItem = pos + 1 ; comboItem < pos + comboLength + 1 ; comboItem + = TriggerGuideSize )
2014-08-05 18:33:55 +00:00
{
2014-08-20 17:53:22 +00:00
// Assign TriggerGuide element (key type, state and scancode)
TriggerGuide * guide = ( TriggerGuide * ) ( & macro - > guide [ comboItem ] ) ;
2014-08-05 18:33:55 +00:00
TriggerMacroVote vote = TriggerMacroVote_Invalid ;
2014-08-20 17:53:22 +00:00
// Iterate through the key buffer, comparing to each key in the combo
for ( uint8_t key = 0 ; key < macroTriggerListBufferSize ; key + + )
2014-08-05 18:33:55 +00:00
{
2014-08-20 17:53:22 +00:00
// Lookup key information
TriggerGuide * keyInfo = & macroTriggerListBuffer [ key ] ;
2014-08-05 18:33:55 +00:00
// If vote is a pass (>= 0x08, no more keys in the combo need to be looked at)
// Also mask all of the non-passing votes
2014-08-20 17:53:22 +00:00
vote | = longMacro
? Macro_evalLongTriggerMacroVote ( keyInfo , guide )
: Macro_evalShortTriggerMacroVote ( keyInfo , guide ) ;
2014-08-05 18:33:55 +00:00
if ( vote > = TriggerMacroVote_Pass )
2014-06-23 03:45:56 +00:00
{
2014-08-05 18:33:55 +00:00
vote & = TriggerMacroVote_Release | TriggerMacroVote_PassRelease | TriggerMacroVote_Pass ;
break ;
2014-06-23 03:45:56 +00:00
}
}
2014-08-05 18:33:55 +00:00
2014-08-20 17:53:22 +00:00
// If no pass vote was found after scanning all of the keys
// Fail the combo, if this is a short macro (long macros already will have a fail vote)
if ( ! longMacro & & vote < TriggerMacroVote_Pass )
vote | = TriggerMacroVote_Fail ;
2014-08-05 18:33:55 +00:00
// After voting, append to overall vote
overallVote | = vote ;
2014-06-23 03:45:56 +00:00
}
2014-08-05 18:33:55 +00:00
2014-08-23 17:49:13 +00:00
// If no pass vote was found after scanning the entire combo
// And this is the first position in the combo, just remove it (nothing important happened)
if ( longMacro & & overallVote & TriggerMacroVote_DoNothingRelease & & pos = = 0 )
overallVote | = TriggerMacroVote_Fail ;
2014-08-05 18:33:55 +00:00
// Decide new state of macro after voting
// Fail macro, remove from pending list
if ( overallVote & TriggerMacroVote_Fail )
{
return TriggerMacroEval_Remove ;
}
// Do nothing, incorrect key is being held or released
2014-08-20 17:53:22 +00:00
else if ( overallVote & TriggerMacroVote_DoNothing & & longMacro )
2014-08-05 18:33:55 +00:00
{
// Just doing nothing :)
}
// If passing and in Waiting state, set macro state to Press
2014-08-20 17:53:22 +00:00
else if ( overallVote & TriggerMacroVote_Pass
& & ( macro - > state = = TriggerMacro_Waiting | | macro - > state = = TriggerMacro_Press ) )
2014-08-05 18:33:55 +00:00
{
macro - > state = TriggerMacro_Press ;
// If in press state, and this is the final combo, send request for ResultMacro
// Check to see if the result macro only has a single element
// If this result macro has more than 1 key, only send once
2014-08-20 17:53:22 +00:00
// TODO Add option to have long macro repeat rate
if ( macro - > guide [ pos + comboLength + 1 ] = = 0 )
2014-08-05 18:33:55 +00:00
{
2014-08-20 17:53:22 +00:00
// Long result macro (more than 1 combo)
if ( Macro_isLongResultMacro ( & ResultMacroList [ macro - > result ] ) )
{
// Only ever trigger result once, on press
if ( overallVote = = TriggerMacroVote_Pass )
{
return TriggerMacroEval_DoResultAndRemove ;
}
}
// Short result macro
else
{
// Only trigger result once, on press, if long trigger (more than 1 combo)
if ( Macro_isLongTriggerMacro ( macro ) )
{
return TriggerMacroEval_DoResultAndRemove ;
}
// Otherwise, trigger result continuously
else
{
return TriggerMacroEval_DoResult ;
}
}
2014-08-05 18:33:55 +00:00
}
}
// If ready for transition and in Press state, set to Waiting and increment combo position
// Position is incremented (and possibly remove the macro from the pending list) on the next iteration
else if ( overallVote & TriggerMacroVote_Release & & macro - > state = = TriggerMacro_Press )
{
macro - > state = TriggerMacro_Release ;
2014-08-20 17:53:22 +00:00
// If this is the last combo in the sequence, remove from the pending list
if ( macro - > guide [ macro - > pos + macro - > guide [ macro - > pos ] * TriggerGuideSize + 1 ] = = 0 )
return TriggerMacroEval_Remove ;
}
// Otherwise, just remove the macro on key release
2014-09-11 03:53:30 +00:00
// One more result has to be called to indicate to the ResultMacro that the key transitioned to the release state
2014-08-20 17:53:22 +00:00
else if ( overallVote & TriggerMacroVote_Release )
{
2014-09-11 03:53:30 +00:00
return TriggerMacroEval_DoResultAndRemove ;
2014-08-05 18:33:55 +00:00
}
2014-08-20 17:53:22 +00:00
// If this is a short macro, just remove it
// The state can be rebuilt on the next iteration
if ( ! longMacro )
return TriggerMacroEval_Remove ;
2014-08-05 18:33:55 +00:00
return TriggerMacroEval_DoNothing ;
2014-06-23 03:45:56 +00:00
}
2014-06-14 18:00:29 +00:00
2014-07-28 06:15:41 +00:00
// Evaluate/Update ResultMacro
2014-09-11 18:17:17 +00:00
inline ResultMacroEval Macro_evalResultMacro ( var_uint_t resultMacroIndex )
2014-04-06 18:49:27 +00:00
{
2014-08-06 19:18:06 +00:00
// Lookup ResultMacro
ResultMacro * macro = & ResultMacroList [ resultMacroIndex ] ;
// Current Macro position
2014-09-11 18:17:17 +00:00
var_uint_t pos = macro - > pos ;
2014-08-06 19:18:06 +00:00
// Length of combo being processed
uint8_t comboLength = macro - > guide [ pos ] ;
// Function Counter, used to keep track of the combo items processed
2014-09-11 18:17:17 +00:00
var_uint_t funcCount = 0 ;
2014-08-06 19:18:06 +00:00
// Combo Item Position within the guide
2014-09-11 18:17:17 +00:00
var_uint_t comboItem = pos + 1 ;
2014-08-06 19:18:06 +00:00
// Iterate through the Result Combo
while ( funcCount < comboLength )
{
// Assign TriggerGuide element (key type, state and scancode)
2014-08-20 17:53:22 +00:00
ResultGuide * guide = ( ResultGuide * ) ( & macro - > guide [ comboItem ] ) ;
2014-08-06 19:18:06 +00:00
// Do lookup on capability function
void ( * capability ) ( uint8_t , uint8_t , uint8_t * ) = ( void ( * ) ( uint8_t , uint8_t , uint8_t * ) ) ( CapabilitiesList [ guide - > index ] . func ) ;
// Call capability
capability ( macro - > state , macro - > stateType , & guide - > args ) ;
// Increment counters
funcCount + + ;
comboItem + = ResultGuideSize ( ( ResultGuide * ) ( & macro - > guide [ comboItem ] ) ) ;
}
// Move to next item in the sequence
macro - > pos = comboItem ;
2014-08-20 17:53:22 +00:00
// If the ResultMacro is finished, remove
if ( macro - > guide [ comboItem ] = = 0 )
{
return ResultMacroEval_Remove ;
}
// Otherwise leave the macro in the list
2014-08-06 19:18:06 +00:00
return ResultMacroEval_DoNothing ;
2014-04-06 18:49:27 +00:00
}
2014-04-26 08:29:09 +00:00
2014-08-05 18:33:55 +00:00
// Update pending trigger list
2014-08-20 17:53:22 +00:00
inline void Macro_updateTriggerMacroPendingList ( )
2014-08-05 18:33:55 +00:00
{
// Iterate over the macroTriggerListBuffer to add any new Trigger Macros to the pending list
for ( uint8_t key = 0 ; key < macroTriggerListBufferSize ; key + + )
{
2014-08-20 17:53:22 +00:00
// TODO LED States
// TODO Analog Switches
// Only add TriggerMacro to pending list if key was pressed (not held, released or off)
if ( macroTriggerListBuffer [ key ] . state = = 0x00 & & macroTriggerListBuffer [ key ] . state ! = 0x01 )
continue ;
2014-08-05 18:33:55 +00:00
// Lookup Trigger List
2014-09-11 17:54:50 +00:00
nat_ptr_t * triggerList = Macro_layerLookup ( macroTriggerListBuffer [ key ] . scanCode ) ;
2014-08-05 18:33:55 +00:00
// Number of Triggers in list
2014-09-11 17:54:50 +00:00
nat_ptr_t triggerListSize = triggerList [ 0 ] ;
2014-08-05 18:33:55 +00:00
// Iterate over triggerList to see if any TriggerMacros need to be added
// First item is the number of items in the TriggerList
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 1 ; macro < triggerListSize + 1 ; macro + + )
2014-08-05 18:33:55 +00:00
{
// Lookup trigger macro index
2014-09-11 18:17:17 +00:00
var_uint_t triggerMacroIndex = triggerList [ macro ] ;
2014-08-05 18:33:55 +00:00
// Iterate over macroTriggerMacroPendingList to see if any macro in the scancode's
// triggerList needs to be added
2014-09-11 18:17:17 +00:00
var_uint_t pending = 0 ;
2014-08-05 18:33:55 +00:00
for ( ; pending < macroTriggerMacroPendingListSize ; pending + + )
{
// Stop scanning if the trigger macro index is found in the pending list
if ( macroTriggerMacroPendingList [ pending ] = = triggerMacroIndex )
break ;
}
// If the triggerMacroIndex (macro) was not found in the macroTriggerMacroPendingList
// Add it to the list
if ( pending = = macroTriggerMacroPendingListSize )
{
macroTriggerMacroPendingList [ macroTriggerMacroPendingListSize + + ] = triggerMacroIndex ;
2014-08-20 17:53:22 +00:00
// Reset macro position
TriggerMacroList [ triggerMacroIndex ] . pos = 0 ;
TriggerMacroList [ triggerMacroIndex ] . state = TriggerMacro_Waiting ;
2014-08-05 18:33:55 +00:00
}
}
}
}
2014-07-28 06:15:41 +00:00
// Macro Procesing Loop
// Called once per USB buffer send
2014-04-06 18:49:27 +00:00
inline void Macro_process ( )
{
// Only do one round of macro processing between Output Module timer sends
if ( USBKeys_Sent ! = 0 )
return ;
2014-07-25 05:22:35 +00:00
// If the pause flag is set, only process if the step counter is non-zero
2014-08-05 18:33:55 +00:00
if ( macroPauseMode )
2014-07-25 05:22:35 +00:00
{
2014-08-05 18:33:55 +00:00
if ( macroStepCounter = = 0 )
return ;
// Proceed, decrementing the step counter
2014-07-25 05:22:35 +00:00
macroStepCounter - - ;
2014-08-15 17:42:12 +00:00
dbug_print ( " Macro Step " ) ;
2014-07-25 05:22:35 +00:00
}
2014-08-05 18:33:55 +00:00
// Update pending trigger list, before processing TriggerMacros
Macro_updateTriggerMacroPendingList ( ) ;
2014-07-28 06:15:41 +00:00
2014-08-05 18:33:55 +00:00
// Tail pointer for macroTriggerMacroPendingList
// Macros must be explicitly re-added
2014-09-11 18:17:17 +00:00
var_uint_t macroTriggerMacroPendingListTail = 0 ;
2014-06-23 03:45:56 +00:00
2014-08-05 18:33:55 +00:00
// Iterate through the pending TriggerMacros, processing each of them
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 0 ; macro < macroTriggerMacroPendingListSize ; macro + + )
2014-08-05 18:33:55 +00:00
{
switch ( Macro_evalTriggerMacro ( macroTriggerMacroPendingList [ macro ] ) )
2014-06-23 03:45:56 +00:00
{
2014-08-05 18:33:55 +00:00
// Trigger Result Macro (purposely falling through)
case TriggerMacroEval_DoResult :
// Append ResultMacro to PendingList
2014-08-20 17:53:22 +00:00
Macro_appendResultMacroToPendingList ( & TriggerMacroList [ macroTriggerMacroPendingList [ macro ] ] ) ;
2014-08-05 18:33:55 +00:00
default :
macroTriggerMacroPendingList [ macroTriggerMacroPendingListTail + + ] = macroTriggerMacroPendingList [ macro ] ;
break ;
2014-06-23 03:45:56 +00:00
2014-08-05 18:33:55 +00:00
// Trigger Result Macro and Remove (purposely falling through)
case TriggerMacroEval_DoResultAndRemove :
// Append ResultMacro to PendingList
2014-08-20 17:53:22 +00:00
Macro_appendResultMacroToPendingList ( & TriggerMacroList [ macroTriggerMacroPendingList [ macro ] ] ) ;
2014-06-23 03:45:56 +00:00
2014-08-05 18:33:55 +00:00
// Remove Macro from Pending List, nothing to do, removing by default
case TriggerMacroEval_Remove :
break ;
2014-06-23 03:45:56 +00:00
}
}
2014-08-06 19:18:06 +00:00
// Update the macroTriggerMacroPendingListSize with the tail pointer
2014-08-05 18:33:55 +00:00
macroTriggerMacroPendingListSize = macroTriggerMacroPendingListTail ;
2014-06-23 03:45:56 +00:00
2014-08-06 19:18:06 +00:00
// Tail pointer for macroResultMacroPendingList
// Macros must be explicitly re-added
2014-09-11 18:17:17 +00:00
var_uint_t macroResultMacroPendingListTail = 0 ;
2014-08-06 19:18:06 +00:00
2014-08-05 18:33:55 +00:00
// Iterate through the pending ResultMacros, processing each of them
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 0 ; macro < macroResultMacroPendingListSize ; macro + + )
2014-08-05 18:33:55 +00:00
{
2014-08-06 19:18:06 +00:00
switch ( Macro_evalResultMacro ( macroResultMacroPendingList [ macro ] ) )
{
// Re-add macros to pending list
case ResultMacroEval_DoNothing :
default :
macroResultMacroPendingList [ macroResultMacroPendingListTail + + ] = macroResultMacroPendingList [ macro ] ;
break ;
// Remove Macro from Pending List, nothing to do, removing by default
case ResultMacroEval_Remove :
break ;
}
2014-08-05 18:33:55 +00:00
}
2014-06-23 03:45:56 +00:00
2014-08-06 19:18:06 +00:00
// Update the macroResultMacroPendingListSize with the tail pointer
macroResultMacroPendingListSize = macroResultMacroPendingListTail ;
// Signal buffer that we've used it
Scan_finishedWithMacro ( macroTriggerListBufferSize ) ;
// Reset TriggerList buffer
macroTriggerListBufferSize = 0 ;
2014-04-06 20:12:31 +00:00
// If Macro debug mode is set, clear the USB Buffer
if ( macroDebugMode )
{
USBKeys_Modifiers = 0 ;
USBKeys_Sent = 0 ;
}
2014-04-06 18:49:27 +00:00
}
2014-07-28 06:15:41 +00:00
2014-04-06 18:49:27 +00:00
inline void Macro_setup ( )
{
// Register Macro CLI dictionary
CLI_registerDictionary ( macroCLIDict , macroCLIDictName ) ;
2014-04-06 20:12:31 +00:00
// Disable Macro debug mode
macroDebugMode = 0 ;
2014-06-23 03:45:56 +00:00
2014-07-25 05:22:35 +00:00
// Disable Macro pause flag
macroPauseMode = 0 ;
// Set Macro step counter to zero
macroStepCounter = 0 ;
2014-06-23 03:45:56 +00:00
// Make sure macro trigger buffer is empty
macroTriggerListBufferSize = 0 ;
2014-08-05 18:33:55 +00:00
// Initialize TriggerMacro states
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 0 ; macro < TriggerMacroNum ; macro + + )
2014-08-05 18:33:55 +00:00
{
2014-08-20 17:53:22 +00:00
TriggerMacroList [ macro ] . pos = 0 ;
TriggerMacroList [ macro ] . state = TriggerMacro_Waiting ;
2014-08-05 18:33:55 +00:00
}
// Initialize ResultMacro states
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 0 ; macro < ResultMacroNum ; macro + + )
2014-08-05 18:33:55 +00:00
{
ResultMacroList [ macro ] . pos = 0 ;
ResultMacroList [ macro ] . state = 0 ;
ResultMacroList [ macro ] . stateType = 0 ;
}
2014-04-06 18:49:27 +00:00
}
// ----- CLI Command Functions -----
void cliFunc_capList ( char * args )
{
2014-07-25 06:18:38 +00:00
print ( NL ) ;
info_msg ( " Capabilities List " ) ;
2014-08-15 17:42:12 +00:00
printHex ( CapabilitiesNum ) ;
2014-07-25 06:18:38 +00:00
// Iterate through all of the capabilities and display them
2014-09-11 18:17:17 +00:00
for ( var_uint_t cap = 0 ; cap < CapabilitiesNum ; cap + + )
2014-07-25 06:18:38 +00:00
{
print ( NL " \t " ) ;
printHex ( cap ) ;
print ( " - " ) ;
// Display/Lookup Capability Name (utilize debug mode of capability)
2014-07-25 17:53:33 +00:00
void ( * capability ) ( uint8_t , uint8_t , uint8_t * ) = ( void ( * ) ( uint8_t , uint8_t , uint8_t * ) ) ( CapabilitiesList [ cap ] . func ) ;
2014-07-25 06:18:38 +00:00
capability ( 0xFF , 0xFF , 0 ) ;
}
2014-04-06 18:49:27 +00:00
}
void cliFunc_capSelect ( char * args )
{
2014-04-06 20:12:31 +00:00
// Parse code from argument
2014-07-25 17:53:33 +00:00
char * curArgs ;
2014-04-06 20:12:31 +00:00
char * arg1Ptr ;
2014-07-25 17:53:33 +00:00
char * arg2Ptr = args ;
// Total number of args to scan (must do a lookup if a keyboard capability is selected)
2014-09-11 18:17:17 +00:00
var_uint_t totalArgs = 2 ; // Always at least two args
var_uint_t cap = 0 ;
2014-04-06 20:12:31 +00:00
2014-07-25 17:53:33 +00:00
// Arguments used for keyboard capability function
2014-09-11 18:17:17 +00:00
var_uint_t argSetCount = 0 ;
2014-07-25 17:53:33 +00:00
uint8_t * argSet = ( uint8_t * ) args ;
// Process all args
2014-09-11 18:17:17 +00:00
for ( var_uint_t c = 0 ; argSetCount < totalArgs ; c + + )
2014-04-06 20:12:31 +00:00
{
2014-07-25 17:53:33 +00:00
curArgs = arg2Ptr ;
CLI_argumentIsolation ( curArgs , & arg1Ptr , & arg2Ptr ) ;
2014-04-06 20:12:31 +00:00
2014-07-25 17:53:33 +00:00
// Stop processing args if no more are found
// Extra arguments are ignored
if ( * arg1Ptr = = ' \0 ' )
break ;
// For the first argument, choose the capability
if ( c = = 0 ) switch ( arg1Ptr [ 0 ] )
2014-04-06 20:12:31 +00:00
{
2014-07-25 17:53:33 +00:00
// Keyboard Capability
case ' K ' :
// Determine capability index
2014-08-16 19:07:25 +00:00
cap = numToInt ( & arg1Ptr [ 1 ] ) ;
2014-07-25 17:53:33 +00:00
// Lookup the number of args
totalArgs + = CapabilitiesList [ cap ] . argCount ;
continue ;
}
// Because allocating memory isn't doable, and the argument count is arbitrary
// The argument pointer is repurposed as the argument list (much smaller anyways)
2014-08-16 19:07:25 +00:00
argSet [ argSetCount + + ] = ( uint8_t ) numToInt ( arg1Ptr ) ;
2014-07-25 17:53:33 +00:00
// Once all the arguments are prepared, call the keyboard capability function
if ( argSetCount = = totalArgs )
{
// Indicate that the capability was called
print ( NL ) ;
info_msg ( " K " ) ;
printInt8 ( cap ) ;
print ( " - " ) ;
printHex ( argSet [ 0 ] ) ;
print ( " - " ) ;
printHex ( argSet [ 1 ] ) ;
print ( " - " ) ;
printHex ( argSet [ 2 ] ) ;
print ( " ... " NL ) ;
void ( * capability ) ( uint8_t , uint8_t , uint8_t * ) = ( void ( * ) ( uint8_t , uint8_t , uint8_t * ) ) ( CapabilitiesList [ cap ] . func ) ;
capability ( argSet [ 0 ] , argSet [ 1 ] , & argSet [ 2 ] ) ;
2014-04-06 20:12:31 +00:00
}
}
2014-04-06 18:49:27 +00:00
}
2014-08-15 17:42:12 +00:00
void cliFunc_keyHold ( char * args )
{
// Parse codes from arguments
char * curArgs ;
char * arg1Ptr ;
char * arg2Ptr = args ;
// Process all args
for ( ; ; )
{
curArgs = arg2Ptr ;
CLI_argumentIsolation ( curArgs , & arg1Ptr , & arg2Ptr ) ;
// Stop processing args if no more are found
if ( * arg1Ptr = = ' \0 ' )
break ;
// Ignore non-Scancode numbers
switch ( arg1Ptr [ 0 ] )
{
// Scancode
case ' S ' :
2014-08-16 19:07:25 +00:00
Macro_keyState ( ( uint8_t ) numToInt ( & arg1Ptr [ 1 ] ) , 0x02 ) ; // Hold scancode
2014-08-15 17:42:12 +00:00
break ;
}
}
}
2014-07-25 05:22:35 +00:00
void cliFunc_keyPress ( char * args )
2014-04-06 18:49:27 +00:00
{
2014-07-25 05:22:35 +00:00
// Parse codes from arguments
char * curArgs ;
2014-04-06 20:12:31 +00:00
char * arg1Ptr ;
2014-07-25 05:22:35 +00:00
char * arg2Ptr = args ;
2014-04-06 20:12:31 +00:00
2014-07-25 05:22:35 +00:00
// Process all args
for ( ; ; )
2014-04-06 20:12:31 +00:00
{
2014-07-25 05:22:35 +00:00
curArgs = arg2Ptr ;
CLI_argumentIsolation ( curArgs , & arg1Ptr , & arg2Ptr ) ;
2014-04-06 20:12:31 +00:00
2014-07-25 05:22:35 +00:00
// Stop processing args if no more are found
if ( * arg1Ptr = = ' \0 ' )
break ;
// Ignore non-Scancode numbers
switch ( arg1Ptr [ 0 ] )
{
// Scancode
case ' S ' :
2014-08-16 19:07:25 +00:00
Macro_keyState ( ( uint8_t ) numToInt ( & arg1Ptr [ 1 ] ) , 0x01 ) ; // Press scancode
2014-07-25 05:22:35 +00:00
break ;
}
2014-04-06 20:12:31 +00:00
}
2014-04-06 18:49:27 +00:00
}
2014-07-25 05:22:35 +00:00
void cliFunc_keyRelease ( char * args )
2014-04-06 18:49:27 +00:00
{
2014-07-25 05:22:35 +00:00
// Parse codes from arguments
char * curArgs ;
2014-04-06 20:12:31 +00:00
char * arg1Ptr ;
2014-07-25 05:22:35 +00:00
char * arg2Ptr = args ;
2014-04-06 20:12:31 +00:00
2014-07-25 05:22:35 +00:00
// Process all args
for ( ; ; )
2014-04-06 20:12:31 +00:00
{
2014-07-25 05:22:35 +00:00
curArgs = arg2Ptr ;
CLI_argumentIsolation ( curArgs , & arg1Ptr , & arg2Ptr ) ;
// Stop processing args if no more are found
if ( * arg1Ptr = = ' \0 ' )
break ;
// Ignore non-Scancode numbers
switch ( arg1Ptr [ 0 ] )
{
// Scancode
case ' S ' :
2014-08-16 19:07:25 +00:00
Macro_keyState ( ( uint8_t ) numToInt ( & arg1Ptr [ 1 ] ) , 0x03 ) ; // Release scancode
2014-07-25 05:22:35 +00:00
break ;
}
2014-04-06 20:12:31 +00:00
}
2014-04-06 18:49:27 +00:00
}
2014-07-25 05:22:35 +00:00
void cliFunc_layerList ( char * args )
{
2014-07-26 19:20:59 +00:00
print ( NL ) ;
info_msg ( " Layer List " ) ;
// Iterate through all of the layers and display them
2014-09-11 18:17:17 +00:00
for ( uint16_t layer = 0 ; layer < LayerNum ; layer + + )
2014-07-26 19:20:59 +00:00
{
print ( NL " \t " ) ;
printHex ( layer ) ;
print ( " - " ) ;
// Display layer name
2014-08-15 17:42:12 +00:00
dPrint ( ( char * ) LayerIndex [ layer ] . name ) ;
2014-07-26 19:20:59 +00:00
// Default map
if ( layer = = 0 )
print ( " \033 [1m(default) \033 [0m " ) ;
// Layer State
print ( NL " \t \t Layer State: " ) ;
2014-09-17 00:04:59 +00:00
printHex ( LayerState [ layer ] ) ;
2014-07-26 19:20:59 +00:00
2014-09-17 00:04:59 +00:00
// First -> Last Indices
print ( " First -> Last Indices: " ) ;
printHex ( LayerIndex [ layer ] . first ) ;
print ( " -> " ) ;
printHex ( LayerIndex [ layer ] . last ) ;
2014-07-26 19:20:59 +00:00
}
2014-07-25 05:22:35 +00:00
}
2014-04-06 20:12:31 +00:00
2014-07-26 19:20:59 +00:00
void cliFunc_layerState ( char * args )
2014-07-25 05:22:35 +00:00
{
2014-07-26 19:20:59 +00:00
// Parse codes from arguments
char * curArgs ;
char * arg1Ptr ;
char * arg2Ptr = args ;
uint8_t arg1 = 0 ;
uint8_t arg2 = 0 ;
// Process first two args
for ( uint8_t c = 0 ; c < 2 ; c + + )
{
curArgs = arg2Ptr ;
CLI_argumentIsolation ( curArgs , & arg1Ptr , & arg2Ptr ) ;
// Stop processing args if no more are found
if ( * arg1Ptr = = ' \0 ' )
break ;
switch ( c )
{
// First argument (e.g. L1)
case 0 :
if ( arg1Ptr [ 0 ] ! = ' L ' )
return ;
2014-08-16 19:07:25 +00:00
arg1 = ( uint8_t ) numToInt ( & arg1Ptr [ 1 ] ) ;
2014-07-26 19:20:59 +00:00
break ;
// Second argument (e.g. 4)
case 1 :
2014-08-16 19:07:25 +00:00
arg2 = ( uint8_t ) numToInt ( arg1Ptr ) ;
2014-07-26 19:20:59 +00:00
// Display operation (to indicate that it worked)
print ( NL ) ;
info_msg ( " Setting Layer L " ) ;
printInt8 ( arg1 ) ;
print ( " to - " ) ;
printHex ( arg2 ) ;
// Set the layer state
2014-09-17 00:04:59 +00:00
LayerState [ arg1 ] = arg2 ;
2014-07-26 19:20:59 +00:00
break ;
}
}
2014-04-06 18:49:27 +00:00
}
void cliFunc_macroDebug ( char * args )
{
2014-04-06 20:12:31 +00:00
// Toggle macro debug mode
macroDebugMode = macroDebugMode ? 0 : 1 ;
print ( NL ) ;
info_msg ( " Macro Debug Mode: " ) ;
printInt8 ( macroDebugMode ) ;
2014-04-06 18:49:27 +00:00
}
2014-07-25 05:22:35 +00:00
void cliFunc_macroList ( char * args )
{
2014-08-15 17:42:12 +00:00
// Show pending key events
print ( NL ) ;
info_msg ( " Pending Key Events: " ) ;
printInt16 ( ( uint16_t ) macroTriggerListBufferSize ) ;
print ( " : " ) ;
for ( uint8_t key = 0 ; key < macroTriggerListBufferSize ; key + + )
{
printHex ( macroTriggerListBuffer [ key ] . scanCode ) ;
print ( " " ) ;
}
// Show pending trigger macros
print ( NL ) ;
info_msg ( " Pending Trigger Macros: " ) ;
printInt16 ( ( uint16_t ) macroTriggerMacroPendingListSize ) ;
print ( " : " ) ;
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 0 ; macro < macroTriggerMacroPendingListSize ; macro + + )
2014-08-15 17:42:12 +00:00
{
printHex ( macroTriggerMacroPendingList [ macro ] ) ;
print ( " " ) ;
}
// Show pending result macros
print ( NL ) ;
info_msg ( " Pending Result Macros: " ) ;
printInt16 ( ( uint16_t ) macroResultMacroPendingListSize ) ;
print ( " : " ) ;
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 0 ; macro < macroResultMacroPendingListSize ; macro + + )
2014-08-15 17:42:12 +00:00
{
printHex ( macroResultMacroPendingList [ macro ] ) ;
print ( " " ) ;
}
2014-07-25 06:42:38 +00:00
// Show available trigger macro indices
print ( NL ) ;
info_msg ( " Trigger Macros Range: T0 -> T " ) ;
printInt16 ( ( uint16_t ) TriggerMacroNum - 1 ) ; // Hopefully large enough :P (can't assume 32-bit)
// Show available result macro indices
print ( NL ) ;
info_msg ( " Result Macros Range: R0 -> R " ) ;
printInt16 ( ( uint16_t ) ResultMacroNum - 1 ) ; // Hopefully large enough :P (can't assume 32-bit)
// Show Trigger to Result Macro Links
print ( NL ) ;
info_msg ( " Trigger : Result Macro Pairs " ) ;
2014-09-11 18:17:17 +00:00
for ( var_uint_t macro = 0 ; macro < TriggerMacroNum ; macro + + )
2014-07-25 06:42:38 +00:00
{
print ( NL ) ;
print ( " \t T " ) ;
printInt16 ( ( uint16_t ) macro ) ; // Hopefully large enough :P (can't assume 32-bit)
print ( " : R " ) ;
printInt16 ( ( uint16_t ) TriggerMacroList [ macro ] . result ) ; // Hopefully large enough :P (can't assume 32-bit)
}
2014-07-25 05:22:35 +00:00
}
void cliFunc_macroProc ( char * args )
{
// Toggle macro pause mode
macroPauseMode = macroPauseMode ? 0 : 1 ;
print ( NL ) ;
info_msg ( " Macro Processing Mode: " ) ;
printInt8 ( macroPauseMode ) ;
}
2014-09-11 18:17:17 +00:00
void macroDebugShowTrigger ( var_uint_t index )
2014-07-25 05:22:35 +00:00
{
// Only proceed if the macro exists
if ( index > = TriggerMacroNum )
return ;
// Trigger Macro Show
TriggerMacro * macro = & TriggerMacroList [ index ] ;
print ( NL ) ;
info_msg ( " Trigger Macro Index: " ) ;
printInt16 ( ( uint16_t ) index ) ; // Hopefully large enough :P (can't assume 32-bit)
print ( NL ) ;
// Read the comboLength for combo in the sequence (sequence of combos)
2014-09-11 18:17:17 +00:00
var_uint_t pos = 0 ;
2014-07-25 05:22:35 +00:00
uint8_t comboLength = macro - > guide [ pos ] ;
// Iterate through and interpret the guide
while ( comboLength ! = 0 )
{
// Initial position of the combo
2014-09-11 18:17:17 +00:00
var_uint_t comboPos = + + pos ;
2014-07-25 05:22:35 +00:00
// Iterate through the combo
while ( pos < comboLength * TriggerGuideSize + comboPos )
{
// Assign TriggerGuide element (key type, state and scancode)
TriggerGuide * guide = ( TriggerGuide * ) ( & macro - > guide [ pos ] ) ;
// Display guide information about trigger key
2014-07-26 21:06:19 +00:00
printHex ( guide - > scanCode ) ;
2014-07-25 05:22:35 +00:00
print ( " | " ) ;
printHex ( guide - > type ) ;
print ( " | " ) ;
printHex ( guide - > state ) ;
// Increment position
pos + = TriggerGuideSize ;
// Only show combo separator if there are combos left in the sequence element
if ( pos < comboLength * TriggerGuideSize + comboPos )
print ( " + " ) ;
}
// Read the next comboLength
comboLength = macro - > guide [ pos ] ;
// Only show sequence separator if there is another combo to process
if ( comboLength ! = 0 )
print ( " ; " ) ;
}
// Display current position
print ( NL " Position: " ) ;
printInt16 ( ( uint16_t ) macro - > pos ) ; // Hopefully large enough :P (can't assume 32-bit)
// Display result macro index
print ( NL " Result Macro Index: " ) ;
printInt16 ( ( uint16_t ) macro - > result ) ; // Hopefully large enough :P (can't assume 32-bit)
2014-08-20 17:53:22 +00:00
// Display trigger macro state
print ( NL " Trigger Macro State: " ) ;
switch ( macro - > state )
{
case TriggerMacro_Press : print ( " Press " ) ; break ;
case TriggerMacro_Release : print ( " Release " ) ; break ;
case TriggerMacro_Waiting : print ( " Waiting " ) ; break ;
}
2014-07-25 05:22:35 +00:00
}
2014-09-11 18:17:17 +00:00
void macroDebugShowResult ( var_uint_t index )
2014-07-25 05:22:35 +00:00
{
// Only proceed if the macro exists
if ( index > = ResultMacroNum )
return ;
// Trigger Macro Show
ResultMacro * macro = & ResultMacroList [ index ] ;
print ( NL ) ;
info_msg ( " Result Macro Index: " ) ;
printInt16 ( ( uint16_t ) index ) ; // Hopefully large enough :P (can't assume 32-bit)
print ( NL ) ;
// Read the comboLength for combo in the sequence (sequence of combos)
2014-09-11 18:17:17 +00:00
var_uint_t pos = 0 ;
2014-07-25 05:22:35 +00:00
uint8_t comboLength = macro - > guide [ pos + + ] ;
// Iterate through and interpret the guide
while ( comboLength ! = 0 )
{
// Function Counter, used to keep track of the combos processed
2014-09-11 18:17:17 +00:00
var_uint_t funcCount = 0 ;
2014-07-25 05:22:35 +00:00
// Iterate through the combo
while ( funcCount < comboLength )
{
// Assign TriggerGuide element (key type, state and scancode)
ResultGuide * guide = ( ResultGuide * ) ( & macro - > guide [ pos ] ) ;
2014-07-25 06:18:38 +00:00
// Display Function Index
printHex ( guide - > index ) ;
print ( " | " ) ;
2014-07-25 05:22:35 +00:00
// Display Function Ptr Address
2014-09-11 18:17:17 +00:00
printHex ( ( nat_ptr_t ) CapabilitiesList [ guide - > index ] . func ) ;
2014-07-25 05:22:35 +00:00
print ( " | " ) ;
// Display/Lookup Capability Name (utilize debug mode of capability)
2014-07-25 17:53:33 +00:00
void ( * capability ) ( uint8_t , uint8_t , uint8_t * ) = ( void ( * ) ( uint8_t , uint8_t , uint8_t * ) ) ( CapabilitiesList [ guide - > index ] . func ) ;
2014-07-25 05:22:35 +00:00
capability ( 0xFF , 0xFF , 0 ) ;
// Display Argument(s)
print ( " ( " ) ;
2014-09-11 18:17:17 +00:00
for ( var_uint_t arg = 0 ; arg < CapabilitiesList [ guide - > index ] . argCount ; arg + + )
2014-07-25 05:22:35 +00:00
{
2014-07-25 06:18:38 +00:00
// Arguments are only 8 bit values
printHex ( ( & guide - > args ) [ arg ] ) ;
2014-07-25 05:22:35 +00:00
// Only show arg separator if there are args left
2014-07-25 17:53:33 +00:00
if ( arg + 1 < CapabilitiesList [ guide - > index ] . argCount )
2014-07-25 05:22:35 +00:00
print ( " , " ) ;
}
print ( " ) " ) ;
// Increment position
pos + = ResultGuideSize ( guide ) ;
// Increment function count
funcCount + + ;
// Only show combo separator if there are combos left in the sequence element
if ( funcCount < comboLength )
print ( " + " ) ;
}
// Read the next comboLength
comboLength = macro - > guide [ pos + + ] ;
// Only show sequence separator if there is another combo to process
if ( comboLength ! = 0 )
print ( " ; " ) ;
}
// Display current position
print ( NL " Position: " ) ;
printInt16 ( ( uint16_t ) macro - > pos ) ; // Hopefully large enough :P (can't assume 32-bit)
// Display final trigger state/type
print ( NL " Final Trigger State (State/Type): " ) ;
printHex ( macro - > state ) ;
print ( " / " ) ;
printHex ( macro - > stateType ) ;
}
void cliFunc_macroShow ( char * args )
{
// Parse codes from arguments
char * curArgs ;
char * arg1Ptr ;
char * arg2Ptr = args ;
// Process all args
for ( ; ; )
{
curArgs = arg2Ptr ;
CLI_argumentIsolation ( curArgs , & arg1Ptr , & arg2Ptr ) ;
// Stop processing args if no more are found
if ( * arg1Ptr = = ' \0 ' )
break ;
// Ignore invalid codes
switch ( arg1Ptr [ 0 ] )
{
// Indexed Trigger Macro
case ' T ' :
2014-08-16 19:07:25 +00:00
macroDebugShowTrigger ( numToInt ( & arg1Ptr [ 1 ] ) ) ;
2014-07-25 05:22:35 +00:00
break ;
// Indexed Result Macro
case ' R ' :
2014-08-16 19:07:25 +00:00
macroDebugShowResult ( numToInt ( & arg1Ptr [ 1 ] ) ) ;
2014-07-25 05:22:35 +00:00
break ;
}
}
}
void cliFunc_macroStep ( char * args )
{
// Parse number from argument
// NOTE: Only first argument is used
char * arg1Ptr ;
char * arg2Ptr ;
CLI_argumentIsolation ( args , & arg1Ptr , & arg2Ptr ) ;
2014-08-15 17:42:12 +00:00
// Default to 1, if no argument given
2014-09-11 18:17:17 +00:00
var_uint_t count = ( var_uint_t ) numToInt ( arg1Ptr ) ;
2014-08-15 17:42:12 +00:00
if ( count = = 0 )
count = 1 ;
2014-07-25 05:22:35 +00:00
// Set the macro step counter, negative int's are cast to uint
2014-08-15 17:42:12 +00:00
macroStepCounter = count ;
2014-07-25 05:22:35 +00:00
}