From a005ad49ad33f6f000066ee225474da31ac6d5d1 Mon Sep 17 00:00:00 2001 From: Jacob Alexander Date: Sat, 6 Sep 2014 12:35:22 -0700 Subject: [PATCH] Adding list to tuple conversion and USBCode to Capabiltiy conversion. --- backends/kiibohd.py | 5 ++ examples/simple2.kll | 7 ++- kll.py | 104 ++++++++++++++++++++++++++++++------------ kll_lib/containers.py | 43 ++++++++++------- 4 files changed, 113 insertions(+), 46 deletions(-) diff --git a/backends/kiibohd.py b/backends/kiibohd.py index 9896c5a..f37e2e6 100644 --- a/backends/kiibohd.py +++ b/backends/kiibohd.py @@ -60,6 +60,11 @@ class Backend: self.tagList.append( item ) + # USB Code Capability Name + def usbCodeCapability( self ): + return "usbKeyOut"; + + # Processes content for fill tags and does any needed dataset calculations def process( self, capabilities ): ## Capabilities ## diff --git a/examples/simple2.kll b/examples/simple2.kll index c89204f..b5611af 100644 --- a/examples/simple2.kll +++ b/examples/simple2.kll @@ -2,16 +2,21 @@ Name = colemak; Author = "HaaTa (Jacob Alexander) 2014"; KLL = 0.3; +usbKeyOut => Output_usbCodeSend_capability( usbCode : 1 ); myCapability2 => myFunc2(); myCapability3 => myFunc3( myArg1 : 2 ); myCapability => myFunc( myArg1 : 1, myArg2 : 4 ); S0x3 : myCapability2(); +S0x4 : myCapability( 0x8, 0x25 ); +S0x12 : U[122] + U[123]; S0x6 : 'abcdDfF'; S0x40 : U[0x1]; S0x40 : U[0x1-0x4]; S0x0B : U["Esc"]; +S0x0B :+ U["Q"]; S[ 0x7 - 0x9 ] : U"6"; S[ 0x7 - 0x9 ], S[0x2,0x3] : U"6"; -S[ 0x2 - 0x9, 0x10 ] : U"r"; +S[ 0x2 - 0x9, 0x10 ] :+ U"r"; +S0x0B :- U["Esc"]; diff --git a/kll.py b/kll.py index 1e477a1..ca91da0 100755 --- a/kll.py +++ b/kll.py @@ -83,9 +83,9 @@ def processCommandLineArgs(): help="Specify .kll files to generate partial map, multiple files per flag.\n" "Each -p defines another partial map.\n" "Base .kll files (that define the scan code maps) must be defined for each partial map." ) - pArgs.add_argument( '-t', '--template', type=str, default="templateKeymap.h", + pArgs.add_argument( '-t', '--template', type=str, default="templates/kiibohdKeymap.h", help="Specify template used to generate the keymap.\n" - "Default: templateKeymap.h" ) + "Default: templates/kiibohdKeymap.h" ) pArgs.add_argument( '-o', '--output', type=str, default="templateKeymap.h", help="Specify output file. Writes to current working directory by default.\n" "Default: generatedKeymap.h" ) @@ -133,10 +133,10 @@ def tokenize( string ): ( 'CodeEnd', ( r'\]', ) ), ( 'String', ( r'"[^"]*"', VERBOSE ) ), ( 'SequenceString', ( r"'[^']*'", ) ), + ( 'Operator', ( r'=>|:\+|:-|:|=', ) ), ( 'Comma', ( r',', ) ), ( 'Dash', ( r'-', ) ), ( 'Plus', ( r'\+', ) ), - ( 'Operator', ( r'=>|:|=', ) ), ( 'Parenthesis', ( r'\(|\)', ) ), ( 'Number', ( r'-?(0x[0-9a-fA-F]+)|(0|([1-9][0-9]*))', VERBOSE ) ), ( 'Name', ( r'[A-Za-z_][A-Za-z_0-9]*', ) ), @@ -155,8 +155,7 @@ def tokenize( string ): ### Parsing ### ## Map Arrays -scanCode_map = [ None ] * 0xFF # Define 8 bit address width -usbCode_map = [ None ] * 0xFF # Define 8 bit address width +macros_map = Macros() variable_dict = dict() capabilities_dict = Capabilities() @@ -301,6 +300,9 @@ eol = a( Token( 'EndOfLine', ';' ) ) def listElem( item ): return [ item ] +def listToTuple( items ): + return tuple( items ) + # Flatten only the top layer (list of lists of ...) def oneLayerFlatten( items ): mainList = [] @@ -357,26 +359,72 @@ def optionExpansion( sequences ): return expandedSequences +# Converts USB Codes into Capabilities +def usbCodeToCapability( items ): + # Items already converted to variants using optionExpansion + for variant in range( 0, len( items ) ): + # Sequence of Combos + for sequence in range( 0, len( items[ variant ] ) ): + for combo in range( 0, len( items[ variant ][ sequence ] ) ): + # Only convert if an integer, otherwise USB Code doesn't need converting + if isinstance( items[ variant ][ sequence ][ combo ], int ): + # Use backend capability name and a single argument + items[ variant ][ sequence ][ combo ] = tuple( [ backend.usbCodeCapability(), tuple( [ items[ variant ][ sequence ][ combo ] ] ) ] ) + + return items + + ## Evaluation Rules -def eval_scanCode( trigger, result ): +def eval_scanCode( triggers, operator, results ): # Convert to lists of lists of lists to tuples of tuples of tuples - trigger = tuple( tuple( tuple( sequence ) for sequence in variant ) for variant in trigger ) - result = tuple( tuple( tuple( sequence ) for sequence in variant ) for variant in result ) + # Tuples are non-mutable, and can be used has index items + 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 ) - # Add to the base scanCode map, overwrite if already defined -# if scanCode_map[ trigger ] != None: -# print ( "ScanCodeMap - Replacing '{0}' with '{1}' -> {2}".format( scanCode_map[ trigger ], result, trigger ) ) -# scanCode_map[ trigger ] = result + # Iterate over all combinations of triggers and results + for trigger in triggers: + for result in results: + # Append Case + if operator == ":+": + macros_map.appendScanCode( trigger, result ) -def eval_usbCode( trigger, result ): - # Check if trigger is list + # Remove Case + elif operator == ":-": + macros_map.removeScanCode( trigger, result ) - # Add to the base usbCode map, overwrite if already defined - if usbCode_map[ trigger ] != None: - print ( "USBCodeMap - Replacing '{0}' with '{1}' -> {2}".format( usbCode_map[ trigger ], result, trigger ) ) - usbCode_map[ trigger ] = result - print ( trigger ) + # Replace Case + elif operator == ":": + macros_map.replaceScanCode( trigger, result ) + + print ( triggers ) + print ( results ) + +def eval_usbCode( triggers, operator, results ): + # Convert to lists of lists of lists to tuples of tuples of tuples + # Tuples are non-mutable, and can be used has index items + 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 ) + + # Iterate over all combinations of triggers and results + for trigger in triggers: + scanCodes = macros_map.lookupUSBCodes( trigger ) + for scanCode in scanCodes: + for result in results: + # Append Case + if operator == ":+": + macros_map.appendScanCode( scanCode, result ) + + # Remove Case + elif operator == ":-": + macros_map.removeScanCode( scanCode, result ) + + # Replace Case + elif operator == ":": + macros_map.replaceScanCode( scanCode, result ) + + #print ( triggers ) + print ( results ) def eval_variable( name, content ): # Content might be a concatenation of multiple data types, convert everything into a single string @@ -435,15 +483,15 @@ usbCode_combo = oneplus( ( usbCode_expanded | usbCode_elem ) + skip( maybe usbCode_sequence = oneplus( ( usbCode_combo | seqString ) + skip( maybe( comma ) ) ) >> oneLayerFlatten # Capabilities -capFunc_arguments = number + skip( maybe( comma ) ) -capFunc_elem = name + skip( parenthesis('(') ) + many( capFunc_arguments ) + skip( parenthesis(')') ) >> listElem +capFunc_arguments = many( number + skip( maybe( comma ) ) ) >> listToTuple +capFunc_elem = name + skip( parenthesis('(') ) + capFunc_arguments + skip( parenthesis(')') ) >> listElem capFunc_combo = oneplus( ( usbCode_expanded | usbCode_elem | capFunc_elem ) + skip( maybe( plus ) ) ) >> listElem capFunc_sequence = oneplus( ( capFunc_combo | seqString ) + skip( maybe( comma ) ) ) >> oneLayerFlatten # Trigger / Result Codes triggerCode_outerList = scanCode_sequence >> optionExpansion -triggerUSBCode_outerList = usbCode_sequence >> optionExpansion -resultCode_outerList = capFunc_sequence >> optionExpansion +triggerUSBCode_outerList = usbCode_sequence >> optionExpansion >> usbCodeToCapability +resultCode_outerList = capFunc_sequence >> optionExpansion >> usbCodeToCapability ## Main Rules @@ -457,8 +505,9 @@ capability_arguments = name + skip( operator(':') ) + number + skip( maybe( com capability_expression = name + skip( operator('=>') ) + name + skip( parenthesis('(') ) + many( capability_arguments ) + skip( parenthesis(')') ) + skip( eol ) >> set_capability #| : ; -scanCode_expression = triggerCode_outerList + skip( operator(':') ) + resultCode_outerList + skip( eol ) >> map_scanCode -usbCode_expression = triggerUSBCode_outerList + skip( operator(':') ) + resultCode_outerList + skip( eol ) #>> map_usbCode +operatorTriggerResult = operator(':') | operator(':+') | operator(':-') +scanCode_expression = triggerCode_outerList + operatorTriggerResult + resultCode_outerList + skip( eol ) >> map_scanCode +usbCode_expression = triggerUSBCode_outerList + operatorTriggerResult + resultCode_outerList + skip( eol ) #>> map_usbCode def parse( tokenSequence ): """Sequence(Token) -> object""" @@ -489,15 +538,14 @@ if __name__ == '__main__': data = file.read() tokenSequence = tokenize( data ) - print ( pformat( tokenSequence ) ) + print ( pformat( tokenSequence ) ) # Display tokenization tree = parse( tokenSequence ) #print ( tree ) - #print ( scanCode_map ) - #print ( usbCode_map ) print ( variable_dict ) print ( capabilities_dict ) # TODO Move + #macros_map.usbCodeToCapability( backend.usbCodeCapability() ) backend.process( capabilities_dict ) # Successful Execution diff --git a/kll_lib/containers.py b/kll_lib/containers.py index b3a2218..5d7bf1d 100644 --- a/kll_lib/containers.py +++ b/kll_lib/containers.py @@ -84,31 +84,40 @@ class Macros: self.layer = 0 # Macro Storage - self.macros = [ [] ] + self.macros = [ dict() ] + + def __repr__( self ): + return "{0}".format( self.macros ) def setLayer( self, layer ): self.layer = layer # Use for ScanCode trigger macros def appendScanCode( self, trigger, result ): - self.macros[ self.layer ][ trigger ] = result + if not trigger in self.macros[ self.layer ]: + self.replaceScanCode( trigger, result ) + else: + self.macros[ self.layer ][ trigger ].append( result ) - # Use for USBCode trigger macros - # An extra lookup is required - def appendUSBCode( self, trigger, result ): - noSuccess = True + # Remove the given trigger/result pair + def removeScanCode( self, trigger, result ): + # Remove all instances of the given trigger/result pair + while result in self.macros[ self.layer ][ trigger ]: + self.macros[ self.layer ][ trigger ].remove( result ) + # Replaces the given trigger with the given result + # If multiple results for a given trigger, clear, then add + def replaceScanCode( self, trigger, result ): + self.macros[ self.layer ][ trigger ] = [ result ] + + # Return a list of ScanCode triggers with the given USB Code trigger + def lookupUSBCodes( self, usbCode ): + scanCodeList = [] + + # Scan current layer for USB Codes for macro in self.macros[ self.layer ].keys(): - # USB Code Found - if trigger == self.macros[ self.layer ][ macro ]: - print ( "USBCode - Replacing '{0}' with '{1}' -> '{2}'".format( trigger, macro, result ) ) - self.macros[ self.layer ][ macro ] = result - noSuccess = False + if usbCode == self.macros[ self.layer ][ macro ]: + scanCodeList.append( macro ) - # Only show warning if no replacements were done - if noSuccess: - print ( "Warning: '{1}' USB Code not found in layer {1}".format( trigger, self.layer ) ) - return False - - return True + return scanCodeList