]> git.donarmstrong.com Git - kiibohd-kll.git/commitdiff
Adding support for Interconnect Nodes
authorJacob Alexander <haata@kiibohd.com>
Sun, 16 Aug 2015 04:29:18 +0000 (21:29 -0700)
committerJacob Alexander <haata@kiibohd.com>
Sun, 16 Aug 2015 04:29:18 +0000 (21:29 -0700)
- Required changing the ScanCode node datastructure
- Interconnect Id's must be stored until the end as it's not possible to calculate the max per node ScanCode until after all the assignments are complete
- Should make future additions more straight-forward (that require per ScanCode information to be stored)

backends/kiibohd.py
kll.py
kll_lib/containers.py
templates/kiibohdDefs.h
templates/kiibohdKeymap.h

index 9f47150451cb706fae115ac54f31be92d83e190f..ae7d97fa5cb6563978931ed3f646b37d8474b15e 100644 (file)
@@ -219,13 +219,17 @@ class Backend( BackendBase ):
 
                        # 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
@@ -254,21 +258,32 @@ class Backend( BackendBase ):
                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
diff --git a/kll.py b/kll.py
index b2ca7efcf43fb49781b93eb02d332eb48bcdd6fe..aab66d27c8fe50ad99bb562292dda469ce44dd50 100755 (executable)
--- a/kll.py
+++ b/kll.py
@@ -478,6 +478,15 @@ def hidCodeToCapability( items ):
        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 ):
@@ -486,8 +495,26 @@ 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 == ":+":
index 2436c7ea930356fd8c00310fa3a938d9e96b9a5e..66aa2f26469492066709293e69108ec41d12bb05 100644 (file)
@@ -34,6 +34,67 @@ ERROR = '\033[5;1;31mERROR\033[0m:'
 
  ## 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 ):
@@ -87,6 +148,9 @@ class Macros:
                # Default layer (0)
                self.layer = 0
 
+               # Unique ScanCode Hash Id Lookup
+               self.scanCodeStore = ScanCodeStore()
+
                # Macro Storage
                self.macros = [ dict() ]
 
@@ -102,6 +166,7 @@ class Macros:
                self.triggerList = []
                self.maxScanCode = []
                self.firstScanCode = []
+               self.interconnectOffset = []
 
                # USBCode Assignment Cache
                self.assignmentCache = []
@@ -199,6 +264,7 @@ class Macros:
        def generate( self ):
                self.generateIndices()
                self.sortIndexLists()
+               self.generateOffsetTable()
                self.generateTriggerLists()
 
        # Generates Index of Results and Triggers
@@ -229,6 +295,34 @@ class Macros:
                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 ) ):
@@ -248,7 +342,8 @@ class 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 ]:
index 00b45a69bdc1d60512fdf4fce062cd212fd750e6..93531b03faf3579f51cfd3a3ee48ecaa9fa29c1c 100644 (file)
@@ -25,5 +25,9 @@
 
 
 // ----- Defines -----
+
+// -- Interconnect Node Maximum --
+<|InterconnectNodeMax|>
+
 <|Defines|>
 
index baf78d9493f629f4e32934ab78c74805e9791d1a..2a8c6d69eb9f4e807b9731e8778855bbef990caf 100644 (file)
 <|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
 //                 _