# Add the trigger macro scan code guide
# See kiibohd controller Macros/PartialMap/kll.h for exact formatting details
- for sequence in range( 0, len( macros.triggersIndexSorted[ trigger ][ 0 ] ) ):
+ for sequence in range( 0, len( macros.triggersIndexSorted[ trigger ][0] ) ):
# For each combo in the sequence, add the length of the combo
self.fill_dict['TriggerMacros'] += "{0}, ".format( len( macros.triggersIndexSorted[ trigger ][0][ sequence ] ) )
# For each combo, add the key type, key state and scan code
- for combo in range( 0, len( macros.triggersIndexSorted[ trigger ][ 0 ][ sequence ] ) ):
- triggerItem = macros.triggersIndexSorted[ trigger ][ 0 ][ sequence ][ combo ]
+ for combo in range( 0, len( macros.triggersIndexSorted[ trigger ][0][ sequence ] ) ):
+ triggerItemId = macros.triggersIndexSorted[ trigger ][0][ sequence ][ combo ]
+
+ # Lookup triggerItem in ScanCodeStore
+ triggerItemObj = macros.scanCodeStore[ triggerItemId ]
+ triggerItem = triggerItemObj.offset( macros.interconnectOffset )
# TODO Add support for Analog keys
# TODO Add support for LED states
self.fill_dict['MaxScanCode'] = "#define MaxScanCode 0x{0:X}".format( macros.overallMaxScanCode )
+ ## Interconnect ScanCode Offset List ##
+ self.fill_dict['ScanCodeInterconnectOffsetList'] = "const uint8_t InterconnectOffsetList[] = {\n"
+ for offset in range( 0, len( macros.interconnectOffset ) ):
+ self.fill_dict['ScanCodeInterconnectOffsetList'] += "\t0x{0:02X},\n".format( macros.interconnectOffset[ offset ] )
+ self.fill_dict['ScanCodeInterconnectOffsetList'] += "};"
+
+
+ ## Max Interconnect Nodes ##
+ self.fill_dict['InterconnectNodeMax'] = "#define InterconnectNodeMax 0x{0:X}\n".format( len( macros.interconnectOffset ) )
+
+
## Default Layer and Default Layer Scan Map ##
self.fill_dict['DefaultLayerTriggerList'] = ""
self.fill_dict['DefaultLayerScanMap'] = "const nat_ptr_t *default_scanMap[] = {\n"
# Iterate over triggerList and generate a C trigger array for the default map and default map array
- for triggerList in range( macros.firstScanCode[ 0 ], len( macros.triggerList[ 0 ] ) ):
+ for triggerList in range( macros.firstScanCode[0], len( macros.triggerList[0] ) ):
# Generate ScanCode index and triggerList length
- self.fill_dict['DefaultLayerTriggerList'] += "Define_TL( default, 0x{0:02X} ) = {{ {1}".format( triggerList, len( macros.triggerList[ 0 ][ triggerList ] ) )
+ self.fill_dict['DefaultLayerTriggerList'] += "Define_TL( default, 0x{0:02X} ) = {{ {1}".format( triggerList, len( macros.triggerList[0][ triggerList ] ) )
# Add scanCode trigger list to Default Layer Scan Map
self.fill_dict['DefaultLayerScanMap'] += "default_tl_0x{0:02X}, ".format( triggerList )
# Add each item of the trigger list
- for trigger in macros.triggerList[ 0 ][ triggerList ]:
- self.fill_dict['DefaultLayerTriggerList'] += ", {0}".format( trigger )
+ for triggerItem in macros.triggerList[0][ triggerList ]:
+ self.fill_dict['DefaultLayerTriggerList'] += ", {0}".format( triggerItem )
self.fill_dict['DefaultLayerTriggerList'] += " };\n"
self.fill_dict['DefaultLayerTriggerList'] = self.fill_dict['DefaultLayerTriggerList'][:-1] # Remove last newline
return items
+# Convert tuple of tuples to list of lists
+def listit( t ):
+ return list( map( listit, t ) ) if isinstance( t, ( list, tuple ) ) else t
+
+# Convert list of lists to tuple of tuples
+def tupleit( t ):
+ return tuple( map( tupleit, t ) ) if isinstance( t, ( tuple, list ) ) else t
+
+
## Evaluation Rules
def eval_scanCode( triggers, operator, results ):
triggers = tuple( tuple( tuple( sequence ) for sequence in variant ) for variant in triggers )
results = tuple( tuple( tuple( sequence ) for sequence in variant ) for variant in results )
+ # Lookup interconnect id (Current file scope)
+ # Default to 0 if not specified
+ if 'ConnectId' not in variables_dict.overallVariables.keys():
+ id_num = 0
+ else:
+ id_num = int( variables_dict.overallVariables['ConnectId'] )
+
# Iterate over all combinations of triggers and results
- for trigger in triggers:
+ for sequence in triggers:
+ # Convert tuple of tuples to list of lists so each element can be modified
+ trigger = listit( sequence )
+
+ # Create ScanCode entries for trigger
+ for seq_index, combo in enumerate( sequence ):
+ for com_index, scancode in enumerate( combo ):
+ trigger[ seq_index ][ com_index ] = macros_map.scanCodeStore.append( ScanCode( scancode, id_num ) )
+
+ # Convert back to a tuple of tuples
+ trigger = tupleit( trigger )
+
for result in results:
# Append Case
if operator == ":+":
## Containers
+class ScanCode:
+ # Container for ScanCodes
+ #
+ # scancode - Non-interconnect adjusted scan code
+ # interconnect_id - Unique id for the interconnect node
+ def __init__( self, scancode, interconnect_id ):
+ self.scancode = scancode
+ self.interconnect_id = interconnect_id
+
+ def __eq__( self, other ):
+ return self.dict() == other.dict()
+
+ def __repr__( self ):
+ return repr( self.dict() )
+
+ def dict( self ):
+ return {
+ 'ScanCode' : self.scancode,
+ 'Id' : self.interconnect_id,
+ }
+
+ # Calculate the actual scancode using the offset list
+ def offset( self, offsetList ):
+ if self.interconnect_id > 0:
+ return self.scancode + offsetList[ self.interconnect_id - 1 ]
+ else:
+ return self.scancode
+
+
+class ScanCodeStore:
+ # Unique lookup for ScanCodes
+ def __init__( self ):
+ self.scancodes = []
+
+ def __getitem__( self, name ):
+ # First check if this is a ScanCode object
+ if isinstance( name, ScanCode ):
+ # Do a reverse lookup
+ for idx, scancode in enumerate( self.scancodes ):
+ if scancode == name:
+ return idx
+
+ # Could not find scancode
+ return None
+
+ # Return scancode using unique id
+ return self.scancodes[ name ]
+
+ # Attempt add ScanCode to list, return unique id
+ def append( self, new_scancode ):
+ # Iterate through list to make sure this is a unique ScanCode
+ for idx, scancode in enumerate( self.scancodes ):
+ if new_scancode == scancode:
+ return idx
+
+ # Unique entry, add to the list
+ self.scancodes.append( new_scancode )
+
+ return len( self.scancodes ) - 1
+
+
class Capabilities:
# Container for capabilities dictionary and convenience functions
def __init__( self ):
# Default layer (0)
self.layer = 0
+ # Unique ScanCode Hash Id Lookup
+ self.scanCodeStore = ScanCodeStore()
+
# Macro Storage
self.macros = [ dict() ]
self.triggerList = []
self.maxScanCode = []
self.firstScanCode = []
+ self.interconnectOffset = []
# USBCode Assignment Cache
self.assignmentCache = []
def generate( self ):
self.generateIndices()
self.sortIndexLists()
+ self.generateOffsetTable()
self.generateTriggerLists()
# Generates Index of Results and Triggers
for trigger in self.triggersIndex.keys():
self.triggersIndexSorted[ self.triggersIndex[ trigger ] ] = trigger
+ # Generates list of offsets for each of the interconnect ids
+ def generateOffsetTable( self ):
+ idMaxScanCode = [ 0 ]
+
+ # Iterate over each layer to get list of max scancodes associated with each interconnect id
+ for layer in range( 0, len( self.macros ) ):
+ # Iterate through each trigger/sequence in the layer
+ for sequence in self.macros[ layer ].keys():
+ # Iterate over the trigger to locate the ScanCodes
+ for combo in sequence:
+ # Iterate over each scancode id in the combo
+ for scancode_id in combo:
+ # Lookup ScanCode
+ scancode_obj = self.scanCodeStore[ scancode_id ]
+
+ # Extend list if not large enough
+ if scancode_obj.interconnect_id >= len( idMaxScanCode ):
+ idMaxScanCode.extend( [ 0 ] * ( scancode_obj.interconnect_id - len( idMaxScanCode ) + 1 ) )
+
+ # Determine if the max seen id for this interconnect id
+ if scancode_obj.scancode > idMaxScanCode[ scancode_obj.interconnect_id ]:
+ idMaxScanCode[ scancode_obj.interconnect_id ] = scancode_obj.scancode
+
+ # Generate interconnect offsets
+ self.interconnectOffset = [ idMaxScanCode[0] + 1 ]
+ for index in range( 1, len( idMaxScanCode ) ):
+ self.interconnectOffset.append( self.interconnectOffset[ index - 1 ] + idMaxScanCode[ index ] )
+
# Generates Trigger Lists per layer using index lists
def generateTriggerLists( self ):
for layer in range( 0, len( self.macros ) ):
# Iterate over the trigger to locate the ScanCodes
for sequence in trigger:
- for combo in sequence:
+ for combo_id in sequence:
+ combo = self.scanCodeStore[ combo_id ].offset( self.interconnectOffset )
# Append triggerIndex for each found scanCode of the Trigger List
# Do not re-add if triggerIndex is already in the Trigger List
if not triggerIndex in self.triggerList[ layer ][ combo ]:
// ----- Defines -----
+
+// -- Interconnect Node Maximum --
+<|InterconnectNodeMax|>
+
<|Defines|>
<|PartialLayerTriggerLists|>
+// -- ScanCode Offset Map
+// Maps interconnect ids to scancode offsets
+//
+// Only used for keyboards with an interconnect
+<|ScanCodeInterconnectOffsetList|>
+
+
// -- ScanCode Indexed Maps
// Maps to a trigger list of macro pointers
// _