a5203da1d4
- Useful for partial redefinitions of keys Such as redefining Shift, which, as per the USB spec is handled by the OS This means we have to careful select which USB Codes to send to the OS to simulate Shift not being pressed (while it is) - KLL capabilities only work with numerical arguments (KLL 0.3d) - Each key must be explicitly block for each combination (e.g. LShift and RShift are handled separately) - Adding example configuration for the Infinity 60% - Adding example configuration for the Infinity Ergodox - Requires kll.git 1a078b2b940709bc3c429c952d2f0d842927394f or higher
1420 lines
38 KiB
C
1420 lines
38 KiB
C
/* Copyright (C) 2014-2016 by Jacob Alexander
|
|
*
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this file. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
// ----- 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"
|
|
#include <generatedKeymap.h> // Generated using kll at compile time, in build directory
|
|
|
|
// Connect Includes
|
|
#if defined(ConnectEnabled_define)
|
|
#include <connect_scan.h>
|
|
#endif
|
|
|
|
// Local Includes
|
|
#include "trigger.h"
|
|
#include "result.h"
|
|
#include "macro.h"
|
|
|
|
|
|
|
|
// ----- Function Declarations -----
|
|
|
|
void cliFunc_capList ( char* args );
|
|
void cliFunc_capSelect ( char* args );
|
|
void cliFunc_keyHold ( char* args );
|
|
void cliFunc_keyPress ( char* args );
|
|
void cliFunc_keyRelease( char* args );
|
|
void cliFunc_layerDebug( char* args );
|
|
void cliFunc_layerList ( char* args );
|
|
void cliFunc_layerState( char* args );
|
|
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 );
|
|
|
|
|
|
|
|
// ----- Variables -----
|
|
|
|
// Macro Module command dictionary
|
|
CLIDict_Entry( capList, "Prints an indexed list of all non USB keycode capabilities." );
|
|
CLIDict_Entry( capSelect, "Triggers the specified capabilities. First two args are state and stateType." NL "\t\t\033[35mK11\033[0m Keyboard Capability 0x0B" );
|
|
CLIDict_Entry( keyHold, "Send key-hold events to the macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A" );
|
|
CLIDict_Entry( keyPress, "Send key-press events to the macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A" );
|
|
CLIDict_Entry( keyRelease, "Send key-release event to macro module. Duplicates have undefined behaviour." NL "\t\t\033[35mS10\033[0m Scancode 0x0A" );
|
|
CLIDict_Entry( layerDebug, "Layer debug mode. Shows layer stack and any changes." );
|
|
CLIDict_Entry( layerList, "List available layers." );
|
|
CLIDict_Entry( layerState, "Modify specified indexed layer state <layer> <state byte>." NL "\t\t\033[35mL2\033[0m Indexed Layer 0x02" NL "\t\t0 Off, 1 Shift, 2 Latch, 4 Lock States" );
|
|
CLIDict_Entry( macroDebug, "Disables/Enables sending USB keycodes to the Output Module and prints U/K codes." );
|
|
CLIDict_Entry( macroList, "List the defined trigger and result macros." );
|
|
CLIDict_Entry( macroProc, "Pause/Resume macro processing." );
|
|
CLIDict_Entry( 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" );
|
|
CLIDict_Entry( macroStep, "Do N macro processing steps. Defaults to 1." );
|
|
|
|
CLIDict_Def( macroCLIDict, "Macro Module Commands" ) = {
|
|
CLIDict_Item( capList ),
|
|
CLIDict_Item( capSelect ),
|
|
CLIDict_Item( keyHold ),
|
|
CLIDict_Item( keyPress ),
|
|
CLIDict_Item( keyRelease ),
|
|
CLIDict_Item( layerDebug ),
|
|
CLIDict_Item( layerList ),
|
|
CLIDict_Item( layerState ),
|
|
CLIDict_Item( macroDebug ),
|
|
CLIDict_Item( macroList ),
|
|
CLIDict_Item( macroProc ),
|
|
CLIDict_Item( macroShow ),
|
|
CLIDict_Item( macroStep ),
|
|
{ 0, 0, 0 } // Null entry for dictionary end
|
|
};
|
|
|
|
|
|
// Layer debug flag - If set, displays any changes to layers and the full layer stack on change
|
|
uint8_t layerDebugMode = 0;
|
|
|
|
// Macro debug flag - If set, clears the USB Buffers after signalling processing completion
|
|
uint8_t macroDebugMode = 0;
|
|
|
|
// 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
|
|
uint16_t macroStepCounter = 0;
|
|
|
|
|
|
// Key Trigger List Buffer and Layer Cache
|
|
// The layer cache is set on press only, hold and release events refer to the value set on press
|
|
TriggerGuide macroTriggerListBuffer[ MaxScanCode ];
|
|
var_uint_t macroTriggerListBufferSize = 0;
|
|
var_uint_t macroTriggerListLayerCache[ MaxScanCode ];
|
|
|
|
// Layer Index Stack
|
|
// * When modifying layer state and the state is non-0x0, the stack must be adjusted
|
|
index_uint_t macroLayerIndexStack[ LayerNum + 1 ] = { 0 };
|
|
index_uint_t macroLayerIndexStackSize = 0;
|
|
|
|
// TODO REMOVE when dependency no longer exists
|
|
extern index_uint_t macroResultMacroPendingList[];
|
|
extern index_uint_t macroResultMacroPendingListSize;
|
|
extern index_uint_t macroTriggerMacroPendingList[];
|
|
extern index_uint_t macroTriggerMacroPendingListSize;
|
|
|
|
// Interconnect ScanCode Cache
|
|
#if defined(ConnectEnabled_define) || defined(PressReleaseCache_define)
|
|
// TODO This can be shrunk by the size of the max node 0 ScanCode
|
|
TriggerGuide macroInterconnectCache[ MaxScanCode ];
|
|
uint8_t macroInterconnectCacheSize = 0;
|
|
#endif
|
|
|
|
// Key blocking buffer
|
|
uint8_t macroHidBlockList[ Macro_maxBlockCount_define ];
|
|
uint8_t macroHidBlockListSize;
|
|
|
|
|
|
|
|
// ----- Capabilities -----
|
|
|
|
// Sets the given layer with the specified layerState
|
|
void Macro_layerState( uint8_t state, uint8_t stateType, uint16_t layer, uint8_t layerState )
|
|
{
|
|
// Ignore if layer does not exist or trying to manipulate layer 0/Default layer
|
|
if ( layer >= LayerNum || layer == 0 )
|
|
return;
|
|
|
|
// Is layer in the LayerIndexStack?
|
|
uint8_t inLayerIndexStack = 0;
|
|
uint16_t stackItem = 0;
|
|
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
|
|
if ( LayerState[ layer ] & layerState )
|
|
{
|
|
// Unset
|
|
LayerState[ layer ] &= ~layerState;
|
|
}
|
|
else
|
|
{
|
|
// Set
|
|
LayerState[ layer ] |= layerState;
|
|
}
|
|
|
|
// 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
|
|
if ( LayerState[ layer ] == 0x00 && inLayerIndexStack )
|
|
{
|
|
// 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--;
|
|
}
|
|
|
|
// Layer Debug Mode
|
|
if ( layerDebugMode )
|
|
{
|
|
dbug_msg("Layer ");
|
|
|
|
// Iterate over each of the layers displaying the state as a hex value
|
|
for ( index_uint_t index = 0; index < LayerNum; index++ )
|
|
{
|
|
printHex_op( LayerState[ index ], 0 );
|
|
}
|
|
|
|
// Always show the default layer (it's always 0)
|
|
print(" 0");
|
|
|
|
// Iterate over the layer stack starting from the bottom of the stack
|
|
for ( index_uint_t index = macroLayerIndexStackSize; index > 0; index-- )
|
|
{
|
|
print(":");
|
|
printHex_op( macroLayerIndexStack[ index - 1 ], 0 );
|
|
}
|
|
|
|
print( NL );
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 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;
|
|
|
|
// Get layer index from arguments
|
|
// Cast pointer to uint8_t to uint16_t then access that memory location
|
|
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;
|
|
}
|
|
|
|
// Only use capability on press
|
|
// TODO Analog
|
|
if ( stateType == 0x00 && state != 0x03 ) // Only on release
|
|
return;
|
|
|
|
// Get layer index from arguments
|
|
// Cast pointer to uint8_t to uint16_t then access that memory location
|
|
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;
|
|
}
|
|
|
|
// 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;
|
|
|
|
// Get layer index from arguments
|
|
// Cast pointer to uint8_t to uint16_t then access that memory location
|
|
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;
|
|
}
|
|
|
|
// Only use capability on press or release
|
|
// TODO Analog
|
|
if ( stateType == 0x00 && ( state == 0x00 || state == 0x02 ) ) // Only pass press or release conditions
|
|
return;
|
|
|
|
// Get layer index from arguments
|
|
// Cast pointer to uint8_t to uint16_t then access that memory location
|
|
uint16_t layer = *(uint16_t*)(&args[0]);
|
|
|
|
Macro_layerState( state, stateType, layer, 0x01 );
|
|
}
|
|
|
|
|
|
// Rotate layer to next/previous
|
|
// Uses state variable to keep track of the current layer position
|
|
// Layers are still evaluated using the layer stack
|
|
uint16_t Macro_rotationLayer;
|
|
void Macro_layerRotate_capability( uint8_t state, uint8_t stateType, uint8_t *args )
|
|
{
|
|
// Display capability name
|
|
if ( stateType == 0xFF && state == 0xFF )
|
|
{
|
|
print("Macro_layerRotate(previous)");
|
|
return;
|
|
}
|
|
|
|
// 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;
|
|
|
|
// Unset previous rotation layer if not 0
|
|
if ( Macro_rotationLayer != 0 )
|
|
{
|
|
Macro_layerState( state, stateType, Macro_rotationLayer, 0x04 );
|
|
}
|
|
|
|
// Get direction of rotation, 0, next, non-zero previous
|
|
uint8_t direction = *args;
|
|
|
|
// Next
|
|
if ( !direction )
|
|
{
|
|
Macro_rotationLayer++;
|
|
|
|
// Invalid layer
|
|
if ( Macro_rotationLayer >= LayerNum )
|
|
Macro_rotationLayer = 0;
|
|
}
|
|
// Previous
|
|
else
|
|
{
|
|
Macro_rotationLayer--;
|
|
|
|
// Layer wrap
|
|
if ( Macro_rotationLayer >= LayerNum )
|
|
Macro_rotationLayer = LayerNum - 1;
|
|
}
|
|
|
|
// Toggle the computed layer rotation
|
|
Macro_layerState( state, stateType, Macro_rotationLayer, 0x04 );
|
|
}
|
|
|
|
|
|
// Block USB Key
|
|
// During the next processing cycle, queue up a key to be ignored
|
|
// e.g. If Shift is assigned to both Shift and Layer 1
|
|
// Then if the 1 key on Layer 1 is assigned 2
|
|
// Block the Shift key so a USB 2 can be sent via the Output channel
|
|
// This works by having a queue of keys to "unset" if they are triggered during the next processing loop
|
|
void Macro_blockUSBKey_capability( uint8_t state, uint8_t stateType, uint8_t *args )
|
|
{
|
|
// Display capability name
|
|
if ( stateType == 0xFF && state == 0xFF )
|
|
{
|
|
print("Macro_blockUSBKey(usbCode)");
|
|
return;
|
|
}
|
|
|
|
// Get usb key from arguments
|
|
// Access argument directly as it's already uint8_t
|
|
uint8_t usbCode = args[0];
|
|
|
|
// Add to the hid block list
|
|
if ( macroHidBlockListSize < Macro_maxBlockCount_define )
|
|
{
|
|
macroHidBlockList[ macroHidBlockListSize++ ] = usbCode;
|
|
}
|
|
else
|
|
{
|
|
warn_print("USB Key Block buffer is full!: ");
|
|
printHex( usbCode );
|
|
print( NL );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ----- Functions -----
|
|
|
|
// Looks up the trigger list for the given scan code (from the active layer)
|
|
// NOTE: Calling function must handle the NULL pointer case
|
|
nat_ptr_t *Macro_layerLookup( TriggerGuide *guide, uint8_t latch_expire )
|
|
{
|
|
uint8_t scanCode = guide->scanCode;
|
|
|
|
// TODO Analog
|
|
// If a normal key, and not pressed, do a layer cache lookup
|
|
if ( guide->type == 0x00 && guide->state != 0x01 )
|
|
{
|
|
// Cached layer
|
|
var_uint_t cachedLayer = macroTriggerListLayerCache[ scanCode ];
|
|
|
|
// Lookup map, then layer
|
|
nat_ptr_t **map = (nat_ptr_t**)LayerIndex[ cachedLayer ].triggerMap;
|
|
const Layer *layer = &LayerIndex[ cachedLayer ];
|
|
|
|
// Cache trigger list before attempting to expire latch
|
|
nat_ptr_t *trigger_list = map[ scanCode - layer->first ];
|
|
|
|
// Check if latch has been pressed for this layer
|
|
uint8_t latch = LayerState[ cachedLayer ] & 0x02;
|
|
if ( latch && latch_expire )
|
|
{
|
|
Macro_layerState( 0, 0, cachedLayer, 0x02 );
|
|
#if defined(ConnectEnabled_define) && defined(LCDEnabled_define)
|
|
// Evaluate the layerStack capability if available (LCD + Interconnect)
|
|
extern void LCD_layerStack_capability( uint8_t state, uint8_t stateType, uint8_t *args );
|
|
LCD_layerStack_capability( 0, 0, 0 );
|
|
#endif
|
|
}
|
|
|
|
return trigger_list;
|
|
}
|
|
|
|
// If no trigger macro is defined at the given layer, fallthrough to the next layer
|
|
for ( uint16_t layerIndex = macroLayerIndexStackSize; layerIndex != 0xFFFF; layerIndex-- )
|
|
{
|
|
// Lookup Layer
|
|
const Layer *layer = &LayerIndex[ macroLayerIndexStack[ layerIndex ] ];
|
|
|
|
// Check if latch has been pressed for this layer
|
|
// XXX Regardless of whether a key is found, the latch is removed on first lookup
|
|
uint8_t latch = LayerState[ macroLayerIndexStack[ layerIndex ] ] & 0x02;
|
|
if ( latch && latch_expire )
|
|
{
|
|
Macro_layerState( 0, 0, macroLayerIndexStack[ layerIndex ], 0x02 );
|
|
}
|
|
|
|
// Only use layer, if state is valid
|
|
// XOR each of the state bits
|
|
// If only two are enabled, do not use this state
|
|
if ( (LayerState[ macroLayerIndexStack[ layerIndex ] ] & 0x01) ^ (latch>>1) ^ ((LayerState[ macroLayerIndexStack[ layerIndex ] ] & 0x04)>>2) )
|
|
{
|
|
// Lookup layer
|
|
nat_ptr_t **map = (nat_ptr_t**)layer->triggerMap;
|
|
|
|
// Determine if layer has key defined
|
|
// Make sure scanCode is between layer first and last scancodes
|
|
if ( map != 0
|
|
&& scanCode <= layer->last
|
|
&& scanCode >= layer->first
|
|
&& *map[ scanCode - layer->first ] != 0 )
|
|
{
|
|
// Set the layer cache
|
|
macroTriggerListLayerCache[ scanCode ] = macroLayerIndexStack[ layerIndex ];
|
|
|
|
return map[ scanCode - layer->first ];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do lookup on default layer
|
|
nat_ptr_t **map = (nat_ptr_t**)LayerIndex[0].triggerMap;
|
|
|
|
// Lookup default layer
|
|
const Layer *layer = &LayerIndex[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 )
|
|
{
|
|
// Set the layer cache to default map
|
|
macroTriggerListLayerCache[ scanCode ] = 0;
|
|
|
|
return map[ scanCode - layer->first ];
|
|
}
|
|
|
|
// Otherwise no defined Trigger Macro
|
|
erro_msg("Scan Code has no defined Trigger Macro: ");
|
|
printHex( scanCode );
|
|
print( NL );
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Add an interconnect ScanCode
|
|
// These are handled differently (less information is sent, hold/off states must be assumed)
|
|
#if defined(ConnectEnabled_define) || defined(PressReleaseCache_define)
|
|
void Macro_pressReleaseAdd( void *trigger_ptr )
|
|
{
|
|
TriggerGuide *trigger = (TriggerGuide*)trigger_ptr;
|
|
|
|
// Error checking
|
|
uint8_t error = 0;
|
|
switch ( trigger->type )
|
|
{
|
|
case 0x00: // Normal key
|
|
switch ( trigger->state )
|
|
{
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x03:
|
|
break;
|
|
default:
|
|
erro_msg("Invalid key state - ");
|
|
error = 1;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// Invalid TriggerGuide type
|
|
default:
|
|
erro_msg("Invalid type - ");
|
|
error = 1;
|
|
break;
|
|
}
|
|
|
|
// Check if ScanCode is out of range
|
|
if ( trigger->scanCode > MaxScanCode )
|
|
{
|
|
warn_msg("ScanCode is out of range/not defined - ");
|
|
error = 1;
|
|
}
|
|
|
|
// Display TriggerGuide
|
|
if ( error )
|
|
{
|
|
printHex( trigger->type );
|
|
print(" ");
|
|
printHex( trigger->state );
|
|
print(" ");
|
|
printHex( trigger->scanCode );
|
|
print( NL );
|
|
return;
|
|
}
|
|
|
|
// Add trigger to the Interconnect Cache
|
|
// During each processing loop, a scancode may be re-added depending on it's state
|
|
for ( var_uint_t c = 0; c < macroInterconnectCacheSize; c++ )
|
|
{
|
|
// Check if the same ScanCode
|
|
if ( macroInterconnectCache[ c ].scanCode == trigger->scanCode )
|
|
{
|
|
// Update the state
|
|
macroInterconnectCache[ c ].state = trigger->state;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// If not in the list, add it
|
|
macroInterconnectCache[ macroInterconnectCacheSize++ ] = *trigger;
|
|
}
|
|
#endif
|
|
|
|
|
|
// Update the scancode key state
|
|
// States:
|
|
// * 0x00 - Off
|
|
// * 0x01 - Pressed
|
|
// * 0x02 - Held
|
|
// * 0x03 - Released
|
|
// * 0x04 - Unpressed (this is currently ignored)
|
|
inline void Macro_keyState( uint8_t scanCode, uint8_t state )
|
|
{
|
|
#if defined(ConnectEnabled_define)
|
|
// Only compile in if a Connect node module is available
|
|
if ( !Connect_master )
|
|
{
|
|
// ScanCodes are only added if there was a state change (on/off)
|
|
switch ( state )
|
|
{
|
|
case 0x00: // Off
|
|
case 0x02: // Held
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Only add to macro trigger list if one of three states
|
|
switch ( state )
|
|
{
|
|
case 0x01: // Pressed
|
|
case 0x02: // Held
|
|
case 0x03: // Released
|
|
// Check if ScanCode is out of range
|
|
if ( scanCode > MaxScanCode )
|
|
{
|
|
warn_msg("ScanCode is out of range/not defined: ");
|
|
printHex( scanCode );
|
|
print( NL );
|
|
return;
|
|
}
|
|
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = scanCode;
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].state = state;
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].type = 0x00; // Normal key
|
|
macroTriggerListBufferSize++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Update the scancode analog state
|
|
// States:
|
|
// * 0x00 - Off
|
|
// * 0x01 - Released
|
|
// * 0x02-0xFF - Analog value (low to high)
|
|
inline void Macro_analogState( uint8_t scanCode, uint8_t state )
|
|
{
|
|
// Only add to macro trigger list if non-off
|
|
// TODO Handle change for interconnect
|
|
if ( state != 0x00 )
|
|
{
|
|
// Check if ScanCode is out of range
|
|
if ( scanCode > MaxScanCode )
|
|
{
|
|
warn_msg("ScanCode is out of range/not defined: ");
|
|
printHex( scanCode );
|
|
print( NL );
|
|
return;
|
|
}
|
|
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = scanCode;
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].state = state;
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].type = 0x02; // Analog key
|
|
macroTriggerListBufferSize++;
|
|
}
|
|
}
|
|
|
|
|
|
// Update led state
|
|
// States:
|
|
// * 0x00 - Off
|
|
// * 0x01 - On
|
|
inline void Macro_ledState( uint8_t ledCode, uint8_t state )
|
|
{
|
|
// Only add to macro trigger list if non-off
|
|
// TODO Handle change for interconnect
|
|
if ( state != 0x00 )
|
|
{
|
|
// Check if LedCode is out of range
|
|
// TODO
|
|
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].scanCode = ledCode;
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].state = state;
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize ].type = 0x01; // LED key
|
|
macroTriggerListBufferSize++;
|
|
}
|
|
}
|
|
|
|
|
|
// Append result macro to pending list, checking for duplicates
|
|
// Do nothing if duplicate
|
|
void Macro_appendResultMacroToPendingList( const TriggerMacro *triggerMacro )
|
|
{
|
|
// Lookup result macro index
|
|
var_uint_t resultMacroIndex = triggerMacro->result;
|
|
|
|
// Iterate through result macro pending list, making sure this macro hasn't been added yet
|
|
for ( var_uint_t macro = 0; macro < macroResultMacroPendingListSize; macro++ )
|
|
{
|
|
// If duplicate found, do nothing
|
|
if ( macroResultMacroPendingList[ macro ] == resultMacroIndex )
|
|
return;
|
|
}
|
|
|
|
// No duplicates found, add to pending list
|
|
macroResultMacroPendingList[ macroResultMacroPendingListSize++ ] = resultMacroIndex;
|
|
|
|
// Lookup scanCode of the last key in the last combo
|
|
var_uint_t pos = 0;
|
|
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 ( var_uint_t keyIndex = 0; keyIndex < macroTriggerListBufferSize; keyIndex++ )
|
|
{
|
|
if ( macroTriggerListBuffer[ keyIndex ].scanCode == scanCode )
|
|
{
|
|
ResultMacroRecordList[ resultMacroIndex ].state = macroTriggerListBuffer[ keyIndex ].state;
|
|
ResultMacroRecordList[ resultMacroIndex ].stateType = macroTriggerListBuffer[ keyIndex ].type;
|
|
}
|
|
}
|
|
|
|
// Reset the macro position
|
|
ResultMacroRecordList[ resultMacroIndex ].pos = 0;
|
|
}
|
|
|
|
|
|
// Block any of the keys that may be in the buffer
|
|
// These keys may not be pressed during the processing loop, but block them anyways
|
|
// See Macro_blockUSBKey_capability for more details on usage
|
|
inline void Macro_processKeyBlocking()
|
|
{
|
|
// Iterate over list of USB keys
|
|
for ( uint8_t key = 0; key < Macro_maxBlockCount_define; key++ )
|
|
{
|
|
// This capability will always unset (doesn't toggle)
|
|
|
|
// First we need to generate the argument
|
|
uint8_t args[] = { macroHidBlockList[ key ] };
|
|
|
|
// XXX Only handles normal keys (no analog, yet)
|
|
// 0x03 is release, which always unsets a key from the USB buffer, even if it's not there
|
|
Output_usbCodeSend_capability( 0x03, 0x00, args );
|
|
}
|
|
}
|
|
|
|
|
|
// Macro Procesing Loop
|
|
// Called once per USB buffer send
|
|
inline void Macro_process()
|
|
{
|
|
#if defined(ConnectEnabled_define)
|
|
// Only compile in if a Connect node module is available
|
|
// If this is a interconnect slave node, send all scancodes to master node
|
|
if ( !Connect_master )
|
|
{
|
|
if ( macroTriggerListBufferSize > 0 )
|
|
{
|
|
Connect_send_ScanCode( Connect_id, macroTriggerListBuffer, macroTriggerListBufferSize );
|
|
macroTriggerListBufferSize = 0;
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Only do one round of macro processing between Output Module timer sends
|
|
if ( USBKeys_Sent != 0 )
|
|
return;
|
|
|
|
#if defined(ConnectEnabled_define) || defined(PressReleaseCache_define)
|
|
#if defined(ConnectEnabled_define)
|
|
// Check if there are any ScanCodes in the interconnect cache to process
|
|
if ( Connect_master && macroInterconnectCacheSize > 0 )
|
|
#endif
|
|
{
|
|
// Iterate over all the cache ScanCodes
|
|
uint8_t currentInterconnectCacheSize = macroInterconnectCacheSize;
|
|
macroInterconnectCacheSize = 0;
|
|
for ( uint8_t c = 0; c < currentInterconnectCacheSize; c++ )
|
|
{
|
|
// Add to the trigger list
|
|
macroTriggerListBuffer[ macroTriggerListBufferSize++ ] = macroInterconnectCache[ c ];
|
|
|
|
// TODO Handle other TriggerGuide types (e.g. analog)
|
|
switch ( macroInterconnectCache[ c ].type )
|
|
{
|
|
// Normal (Press/Hold/Release)
|
|
case 0x00:
|
|
// Decide what to do based on the current state
|
|
switch ( macroInterconnectCache[ c ].state )
|
|
{
|
|
// Re-add to interconnect cache in hold state
|
|
case 0x01: // Press
|
|
//case 0x02: // Hold // XXX Why does this not work? -HaaTa
|
|
macroInterconnectCache[ c ].state = 0x02;
|
|
macroInterconnectCache[ macroInterconnectCacheSize++ ] = macroInterconnectCache[ c ];
|
|
break;
|
|
case 0x03: // Remove
|
|
break;
|
|
// Otherwise, do not re-add
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// If the pause flag is set, only process if the step counter is non-zero
|
|
if ( macroPauseMode )
|
|
{
|
|
if ( macroStepCounter == 0 )
|
|
return;
|
|
|
|
// Proceed, decrementing the step counter
|
|
macroStepCounter--;
|
|
dbug_print("Macro Step");
|
|
}
|
|
|
|
// Process Trigger Macros
|
|
Trigger_process();
|
|
|
|
|
|
// Process result macros
|
|
Result_process();
|
|
|
|
// Process Key Blocking
|
|
Macro_processKeyBlocking();
|
|
|
|
// Signal buffer that we've used it
|
|
Scan_finishedWithMacro( macroTriggerListBufferSize );
|
|
|
|
// Reset TriggerList buffer
|
|
macroTriggerListBufferSize = 0;
|
|
|
|
// If Macro debug mode is set, clear the USB Buffer
|
|
if ( macroDebugMode )
|
|
{
|
|
USBKeys_Modifiers = 0;
|
|
USBKeys_Sent = 0;
|
|
}
|
|
}
|
|
|
|
|
|
inline void Macro_setup()
|
|
{
|
|
// Register Macro CLI dictionary
|
|
CLI_registerDictionary( macroCLIDict, macroCLIDictName );
|
|
|
|
// Disable Macro debug mode
|
|
macroDebugMode = 0;
|
|
|
|
// Disable Macro pause flag
|
|
macroPauseMode = 0;
|
|
|
|
// Set Macro step counter to zero
|
|
macroStepCounter = 0;
|
|
|
|
// Make sure macro trigger buffer is empty
|
|
macroTriggerListBufferSize = 0;
|
|
|
|
// Set the current rotated layer to 0
|
|
Macro_rotationLayer = 0;
|
|
|
|
// Setup Triggers
|
|
Trigger_setup();
|
|
|
|
// Setup Results
|
|
Result_setup();
|
|
}
|
|
|
|
|
|
// ----- CLI Command Functions -----
|
|
|
|
void cliFunc_capList( char* args )
|
|
{
|
|
print( NL );
|
|
info_msg("Capabilities List ");
|
|
printHex( CapabilitiesNum );
|
|
|
|
// Iterate through all of the capabilities and display them
|
|
for ( var_uint_t cap = 0; cap < CapabilitiesNum; cap++ )
|
|
{
|
|
print( NL "\t" );
|
|
printHex( cap );
|
|
print(" - ");
|
|
|
|
// Display/Lookup Capability Name (utilize debug mode of capability)
|
|
void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ cap ].func);
|
|
capability( 0xFF, 0xFF, 0 );
|
|
}
|
|
}
|
|
|
|
void cliFunc_capSelect( char* args )
|
|
{
|
|
// Parse code from argument
|
|
char* curArgs;
|
|
char* arg1Ptr;
|
|
char* arg2Ptr = args;
|
|
|
|
// Total number of args to scan (must do a lookup if a keyboard capability is selected)
|
|
var_uint_t totalArgs = 2; // Always at least two args
|
|
var_uint_t cap = 0;
|
|
|
|
// Arguments used for keyboard capability function
|
|
var_uint_t argSetCount = 0;
|
|
uint8_t *argSet = (uint8_t*)args;
|
|
|
|
// Process all args
|
|
for ( var_uint_t c = 0; argSetCount < totalArgs; c++ )
|
|
{
|
|
curArgs = arg2Ptr;
|
|
CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
|
|
|
|
// 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] )
|
|
{
|
|
// Keyboard Capability
|
|
case 'K':
|
|
// Determine capability index
|
|
cap = numToInt( &arg1Ptr[1] );
|
|
|
|
// 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)
|
|
argSet[ argSetCount++ ] = (uint8_t)numToInt( arg1Ptr );
|
|
|
|
// 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 );
|
|
|
|
// Make sure this isn't the reload capability
|
|
// If it is, and the remote reflash define is not set, ignore
|
|
if ( flashModeEnabled_define == 0 ) for ( uint32_t cap = 0; cap < CapabilitiesNum; cap++ )
|
|
{
|
|
if ( CapabilitiesList[ cap ].func == (const void*)Output_flashMode_capability )
|
|
{
|
|
print( NL );
|
|
warn_print("flashModeEnabled not set, cancelling firmware reload...");
|
|
info_msg("Set flashModeEnabled to 1 in your kll configuration.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
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] );
|
|
}
|
|
}
|
|
}
|
|
|
|
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':
|
|
Macro_keyState( (uint8_t)numToInt( &arg1Ptr[1] ), 0x02 ); // Hold scancode
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cliFunc_keyPress( 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':
|
|
Macro_keyState( (uint8_t)numToInt( &arg1Ptr[1] ), 0x01 ); // Press scancode
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cliFunc_keyRelease( 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':
|
|
Macro_keyState( (uint8_t)numToInt( &arg1Ptr[1] ), 0x03 ); // Release scancode
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cliFunc_layerDebug( char *args )
|
|
{
|
|
// Toggle layer debug mode
|
|
layerDebugMode = layerDebugMode ? 0 : 1;
|
|
|
|
print( NL );
|
|
info_msg("Layer Debug Mode: ");
|
|
printInt8( layerDebugMode );
|
|
}
|
|
|
|
void cliFunc_layerList( char* args )
|
|
{
|
|
print( NL );
|
|
info_msg("Layer List");
|
|
|
|
// Iterate through all of the layers and display them
|
|
for ( uint16_t layer = 0; layer < LayerNum; layer++ )
|
|
{
|
|
print( NL "\t" );
|
|
printHex( layer );
|
|
print(" - ");
|
|
|
|
// Display layer name
|
|
dPrint( (char*)LayerIndex[ layer ].name );
|
|
|
|
// Default map
|
|
if ( layer == 0 )
|
|
print(" \033[1m(default)\033[0m");
|
|
|
|
// Layer State
|
|
print( NL "\t\t Layer State: " );
|
|
printHex( LayerState[ layer ] );
|
|
|
|
// First -> Last Indices
|
|
print(" First -> Last Indices: ");
|
|
printHex( LayerIndex[ layer ].first );
|
|
print(" -> ");
|
|
printHex( LayerIndex[ layer ].last );
|
|
}
|
|
}
|
|
|
|
void cliFunc_layerState( char* args )
|
|
{
|
|
// 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;
|
|
|
|
arg1 = (uint8_t)numToInt( &arg1Ptr[1] );
|
|
break;
|
|
// Second argument (e.g. 4)
|
|
case 1:
|
|
arg2 = (uint8_t)numToInt( arg1Ptr );
|
|
|
|
// Display operation (to indicate that it worked)
|
|
print( NL );
|
|
info_msg("Setting Layer L");
|
|
printInt8( arg1 );
|
|
print(" to - ");
|
|
printHex( arg2 );
|
|
|
|
// Set the layer state
|
|
LayerState[ arg1 ] = arg2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cliFunc_macroDebug( char* args )
|
|
{
|
|
// Toggle macro debug mode
|
|
macroDebugMode = macroDebugMode ? 0 : 1;
|
|
|
|
print( NL );
|
|
info_msg("Macro Debug Mode: ");
|
|
printInt8( macroDebugMode );
|
|
}
|
|
|
|
void cliFunc_macroList( char* args )
|
|
{
|
|
// Show pending key events
|
|
print( NL );
|
|
info_msg("Pending Key Events: ");
|
|
printInt16( (uint16_t)macroTriggerListBufferSize );
|
|
print(" : ");
|
|
for ( var_uint_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(" : ");
|
|
for ( var_uint_t macro = 0; macro < macroTriggerMacroPendingListSize; macro++ )
|
|
{
|
|
printHex( macroTriggerMacroPendingList[ macro ] );
|
|
print(" ");
|
|
}
|
|
|
|
// Show pending result macros
|
|
print( NL );
|
|
info_msg("Pending Result Macros: ");
|
|
printInt16( (uint16_t)macroResultMacroPendingListSize );
|
|
print(" : ");
|
|
for ( var_uint_t macro = 0; macro < macroResultMacroPendingListSize; macro++ )
|
|
{
|
|
printHex( macroResultMacroPendingList[ macro ] );
|
|
print(" ");
|
|
}
|
|
|
|
// 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");
|
|
for ( var_uint_t macro = 0; macro < TriggerMacroNum; macro++ )
|
|
{
|
|
print( NL );
|
|
print("\tT");
|
|
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)
|
|
}
|
|
}
|
|
|
|
void cliFunc_macroProc( char* args )
|
|
{
|
|
// Toggle macro pause mode
|
|
macroPauseMode = macroPauseMode ? 0 : 1;
|
|
|
|
print( NL );
|
|
info_msg("Macro Processing Mode: ");
|
|
printInt8( macroPauseMode );
|
|
}
|
|
|
|
void macroDebugShowTrigger( var_uint_t index )
|
|
{
|
|
// Only proceed if the macro exists
|
|
if ( index >= TriggerMacroNum )
|
|
return;
|
|
|
|
// Trigger Macro Show
|
|
const TriggerMacro *macro = &TriggerMacroList[ index ];
|
|
TriggerMacroRecord *record = &TriggerMacroRecordList[ 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)
|
|
var_uint_t pos = 0;
|
|
uint8_t comboLength = macro->guide[ pos ];
|
|
|
|
// Iterate through and interpret the guide
|
|
while ( comboLength != 0 )
|
|
{
|
|
// Initial position of the combo
|
|
var_uint_t comboPos = ++pos;
|
|
|
|
// Iterate through the combo
|
|
while ( pos < comboLength * TriggerGuideSize + comboPos )
|
|
{
|
|
// Assign TriggerGuide element (key type, state and scancode)
|
|
TriggerGuide *guide = (TriggerGuide*)(¯o->guide[ pos ]);
|
|
|
|
// Display guide information about trigger key
|
|
printHex( guide->scanCode );
|
|
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)record->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)
|
|
|
|
// Display trigger macro state
|
|
print( NL "Trigger Macro State: " );
|
|
switch ( record->state )
|
|
{
|
|
case TriggerMacro_Press: print("Press"); break;
|
|
case TriggerMacro_Release: print("Release"); break;
|
|
case TriggerMacro_Waiting: print("Waiting"); break;
|
|
}
|
|
}
|
|
|
|
void macroDebugShowResult( var_uint_t index )
|
|
{
|
|
// Only proceed if the macro exists
|
|
if ( index >= ResultMacroNum )
|
|
return;
|
|
|
|
// Trigger Macro Show
|
|
const ResultMacro *macro = &ResultMacroList[ index ];
|
|
ResultMacroRecord *record = &ResultMacroRecordList[ 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)
|
|
var_uint_t pos = 0;
|
|
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
|
|
var_uint_t funcCount = 0;
|
|
|
|
// Iterate through the combo
|
|
while ( funcCount < comboLength )
|
|
{
|
|
// Assign TriggerGuide element (key type, state and scancode)
|
|
ResultGuide *guide = (ResultGuide*)(¯o->guide[ pos ]);
|
|
|
|
// Display Function Index
|
|
printHex( guide->index );
|
|
print("|");
|
|
|
|
// Display Function Ptr Address
|
|
printHex( (nat_ptr_t)CapabilitiesList[ guide->index ].func );
|
|
print("|");
|
|
|
|
// Display/Lookup Capability Name (utilize debug mode of capability)
|
|
void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ guide->index ].func);
|
|
capability( 0xFF, 0xFF, 0 );
|
|
|
|
// Display Argument(s)
|
|
print("(");
|
|
for ( var_uint_t arg = 0; arg < CapabilitiesList[ guide->index ].argCount; arg++ )
|
|
{
|
|
// Arguments are only 8 bit values
|
|
printHex( (&guide->args)[ arg ] );
|
|
|
|
// Only show arg separator if there are args left
|
|
if ( arg + 1 < CapabilitiesList[ guide->index ].argCount )
|
|
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)record->pos ); // Hopefully large enough :P (can't assume 32-bit)
|
|
|
|
// Display final trigger state/type
|
|
print( NL "Final Trigger State (State/Type): " );
|
|
printHex( record->state );
|
|
print("/");
|
|
printHex( record->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':
|
|
macroDebugShowTrigger( numToInt( &arg1Ptr[1] ) );
|
|
break;
|
|
// Indexed Result Macro
|
|
case 'R':
|
|
macroDebugShowResult( numToInt( &arg1Ptr[1] ) );
|
|
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 );
|
|
|
|
// Default to 1, if no argument given
|
|
var_uint_t count = (var_uint_t)numToInt( arg1Ptr );
|
|
|
|
if ( count == 0 )
|
|
count = 1;
|
|
|
|
// Set the macro step counter, negative int's are cast to uint
|
|
macroStepCounter = count;
|
|
}
|
|
|