diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/common/channel.py b/common/channel.py new file mode 100644 index 0000000..45e014d --- /dev/null +++ b/common/channel.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +''' +KLL Channel Containers +''' + +# Copyright (C) 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 . + +### Imports ### + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +class Channel: + ''' + Pixel Channel Container + ''' + def __init__( self, uid, width ): + self.uid = uid + self.width = width + + def __repr__( self ): + return "{0}:{1}".format( self.uid, self.width ) + + +class ChannelList: + ''' + Pixel Channel List Container + ''' + def __init__( self ): + self.channels = [] + + def setChannels( self, channel_list ): + ''' + Apply channels to Pixel + ''' + for channel in channel_list: + self.channels.append( Channel( channel[0], channel[1] ) ) + + def strChannels( self ): + ''' + __repr__ of Channel when multiple inheritance is used + ''' + output = "" + for index, channel in enumerate( self.channels ): + if index > 0: + output += "," + output += "{0}".format( channel ) + + return output + + def __repr__( self ): + return self.strChannels() + diff --git a/common/context.py b/common/context.py new file mode 100644 index 0000000..f86dbc1 --- /dev/null +++ b/common/context.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python3 +''' +KLL Context Definitions +* Generic (auto-detected) +* Configuration +* BaseMap +* DefaultMap +* PartialMap +''' + +# Copyright (C) 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 . + +### Imports ### + +import copy +import os + +import common.organization as organization + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +class Context: + ''' + Base KLL Context Class + ''' + def __init__( self ): + ''' + Context initialization + ''' + # Each context may have one or more included kll files + # And each of these files will have at least 1 Context + self.kll_files = [] + + # File data assigned to each context + # This info is populated during the PreprocessorStage + self.lines = [] + self.data = "" + self.parent = None + + # Tokenized data sets + self.classification_token_data = [] + self.expressions = [] + + # Organized Expression Datastructure + self.organization = organization.Organization() + + def __repr__( self ): + # Build list of all the info + return "(kll_files={0}, lines={1}, data='''{2}''')".format( + self.kll_files, + self.lines, + self.data, + ) + + def initial_context( self, lines, data, parent ): + ''' + Used in the PreprocessorStage to update the initial line and kll file data + + @param lines: Data split per line + @param data: Entire context in a single string + @param parent: Parent node, always a KLLFile + ''' + self.lines = lines + self.data = data + self.parent = parent + + def query( self, kll_expression, kll_type ): + ''' + Query + + Returns a dictionary of the specified property. + Most queries should use this. + + See organization.py:Organization for property_type details. + + @param kll_expression: String name of expression type + @param kll_type: String name of the expression sub-type + + @return: context_name: (dictionary) + ''' + return self.organization.data_mapping[ kll_expression ][ kll_type ] + + +class GenericContext( Context ): + ''' + Generic KLL Context Class + ''' + + +class ConfigurationContext( Context ): + ''' + Configuration KLL Context Class + ''' + + +class BaseMapContext( Context ): + ''' + Base Map KLL Context Class + ''' + + +class DefaultMapContext( Context ): + ''' + Default Map KLL Context Class + ''' + + +class PartialMapContext( Context ): + ''' + Partial Map KLL Context Class + ''' + def __init__( self, layer ): + ''' + Partial Map Layer Context Initialization + + @param: Layer associated with Partial Map + ''' + super().__init__() + + self.layer = layer + + +class MergeContext( Context ): + ''' + Container class for a merged Context + + Has references to the original contexts merged in + ''' + def __init__( self, base_context ): + ''' + Initialize the MergeContext with the base context + Another MergeContext can be used as the base_context + + @param base_context: Context used to seed the MergeContext + ''' + super().__init__() + + # List of context, in the order of merging, starting from the base + self.contexts = [ base_context ] + + # Copy the base context Organization into the MergeContext + self.organization = copy.copy( base_context.organization ) + + # Set the layer if the base is a PartialMapContext + if base_context.__class__.__name__ == 'PartialMapContext': + self.layer = base_context.layer + + def merge( self, merge_in, debug ): + ''' + Merge in context + + Another MergeContext can be merged into a MergeContext + + @param merge_in: Context to merge in to this one + @param debug: Enable debug out + ''' + # Append to context list + self.contexts.append( merge_in ) + + # Merge context + self.organization.merge( + merge_in.organization, + debug + ) + + # Set the layer if the base is a PartialMapContext + if merge_in.__class__.__name__ == 'PartialMapContext': + self.layer = merge_in.layer + + def reduction( self ): + ''' + Simplifies datastructure + + NOTE: This will remove data, therefore, context is lost + ''' + self.organization.reduction() + + def paths( self ): + ''' + Returns list of file paths used to generate this context + ''' + file_paths = [] + + for kll_context in self.contexts: + # If context is a MergeContext then we have to recursively search + if kll_context.__class__.__name__ is 'MergeContext': + file_paths.extend( kll_context.paths() ) + else: + file_paths.append( kll_context.parent.path ) + + return file_paths + + def files( self ): + ''' + Short form list of file paths used to generate this context + ''' + file_paths = [] + for file_path in self.paths(): + file_paths.append( os.path.basename( file_path ) ) + + return file_paths + + def __repr__( self ): + return "(kll_files={0}, organization={1})".format( + self.files(), + self.organization, + ) + + def query_contexts( self, kll_expression, kll_type ): + ''' + Context Query + + Returns a list of tuples (dictionary, kll_context) doing a deep search to the context leaf nodes. + This results in pre-merge data and is useful for querying information about files used during compilation. + + See organization.py:Organization for property_type details. + + @param kll_expression: String name of expression type + @param kll_type: String name of the expression sub-type + + @return: context_name: (dictionary, kll_context) + ''' + # Build list of leaf contexts + leaf_contexts = [] + for kll_context in self.contexts: + # Recursively search if necessary + if kll_context.__class__.__name__ == 'MergeContext': + leaf_contexts.extend( kll_context.query_contexts( kll_expression, kll_type ) ) + else: + leaf_contexts.append( ( kll_context.query( kll_expression, kll_type ), kll_context ) ) + + return leaf_contexts + diff --git a/common/emitter.py b/common/emitter.py new file mode 100644 index 0000000..37bfcf4 --- /dev/null +++ b/common/emitter.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +''' +KLL Emitter Base Classes +''' + +# Copyright (C) 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 . + +### Imports ### + +import re +import os +import sys + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +class Emitter: + ''' + KLL Emitter Base Class + + NOTE: Emitter should do as little as possible in the __init__ function. + ''' + def __init__( self, control ): + ''' + Emitter initialization + + @param control: ControlStage object, used to access data from other stages + ''' + self.control = control + self.color = False + + def command_line_args( self, args ): + ''' + Group parser for command line arguments + + @param args: Name space of processed arguments + ''' + print( "{0} '{1}' '{2}' has not been implemented yet" + .format( + WARNING, + self.command_line_args.__name__, + type( self ).__name__ + ) + ) + + def command_line_flags( self, parser ): + ''' + Group parser for command line options + + @param parser: argparse setup object + ''' + print( "{0} '{1}' '{2}' has not been implemented yet" + .format( + WARNING, + self.command_line_flags.__name__, + type( self ).__name__ + ) + ) + + def process( self ): + ''' + Emitter Processing + ''' + print( "{0} '{1}' '{2}' has not been implemented yet" + .format( + WARNING, + self.process.__name__, + type( self ).__name__ + ) + ) + + def output( self ): + ''' + Final Stage of Emitter + + Generate desired outputs + ''' + print( "{0} '{1}' '{2}' has not been implemented yet" + .format( + WARNING, + self.output.__name__, + type( self ).__name__ + ) + ) + + +class TextEmitter: + ''' + KLL Text Emitter Class + + Base class for any text emitter that wants to use the templating functionality + + If multiple files need to be generated, call load_template and generate multiple times. + e.g. + load_template('_myfile.h') + generate('/tmp/myfile.h') + + load_template('_myfile2.h') + generate('/tmp/myfile2.h') + + TODO + - Generate list of unused tags + ''' + def __init__( self ): + ''' + TextEmitter Initialization + ''' + # Dictionary used to do template replacements + self.fill_dict = {} + self.tag_list = [] + + self.template = None + + def load_template( self, template ): + ''' + Loads template file + + Looks for <|tags|> to replace in the template + + @param template: Path to template + ''' + + # Does template exist? + if not os.path.isfile( template ): + print ( "{0} '{1}' does not exist...".format( ERROR, template ) ) + sys.exit( 1 ) + + self.template = template + + # Generate list of fill tags + with open( template, 'r' ) as openFile: + for line in openFile: + match = re.findall( r'<\|([^|>]+)\|>', line ) + for item in match: + self.tag_list.append( item ) + + def generate( self, output_path ): + ''' + Generates the output file from the template file + + @param output_path: Path to the generated file + ''' + # Make sure we've called load_template at least once + if self.template is None: + print ( "{0} TextEmitter template (load_template) has not been called.".format( ERROR ) ) + sys.exit( 1 ) + + # Process each line of the template, outputting to the target path + with open( output_path, 'w' ) as outputFile: + with open( self.template, 'r' ) as templateFile: + for line in templateFile: + # TODO Support multiple replacements per line + # TODO Support replacement with other text inline + match = re.findall( r'<\|([^|>]+)\|>', line ) + + # If match, replace with processed variable + if match: + try: + outputFile.write( self.fill_dict[ match[0] ] ) + except KeyError as err: + print( "{0} '{1}' not found, skipping...".format( + WARNING, match[0] + ) ) + outputFile.write("\n") + + # Otherwise, just append template to output file + else: + outputFile.write( line ) + diff --git a/common/expression.py b/common/expression.py new file mode 100644 index 0000000..02da8e8 --- /dev/null +++ b/common/expression.py @@ -0,0 +1,630 @@ +#!/usr/bin/env python3 +''' +KLL Expression Container +''' + +# Copyright (C) 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 . + +### Imports ### + +import copy + +from common.id import CapId + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +class Expression: + ''' + Container class for KLL expressions + ''' + def __init__( self, lparam, operator, rparam, context ): + ''' + Initialize expression container + + @param lparam: LOperatorData token + @param operator: Operator token + @param rparam: ROperatorData token + @param context: Parent context of expression + ''' + # First stage/init + self.lparam_token = lparam + self.operator_token = operator + self.rparam_token = rparam + self.context = context # TODO, set multiple contexts for later stages + + # Second stage + self.lparam_sub_tokens = [] + self.rparam_sub_tokens = [] + + # Mutate class into the desired type + self.__class__ = { + '=>' : NameAssociationExpression, + '<=' : DataAssociationExpression, + '=' : AssignmentExpression, + ':' : MapExpression, + }[ self.operator_type() ] + + def operator_type( self ): + ''' + Determine which base operator this operator is of + + All : (map) expressions are tokenized/parsed the same way + + @return Base string representation of the operator + ''' + if ':' in self.operator_token.value: + return ':' + + return self.operator_token.value + + + def final_tokens( self, no_filter=False ): + ''' + Return the final list of tokens, must complete the second stage first + + @param no_filter: If true, do not filter out Space tokens + + @return Finalized list of tokens + ''' + ret = self.lparam_sub_tokens + [ self.operator_token ] + self.rparam_sub_tokens + + if not no_filter: + ret = [ x for x in ret if x.type != 'Space' ] + return ret + + def regen_str( self ): + ''' + Re-construct the string based off the original set of tokens + + ; + ''' + return "{0}{1}{2};".format( + self.lparam_token.value, + self.operator_token.value, + self.rparam_token.value, + ) + + def point_chars( self, pos_list ): + ''' + Using the regenerated string, point to a given list of characters + Used to indicate where a possible issue/syntax error is + + @param pos_list: List of character indices + + i.e. + > U"A" : : U"1"; + > ^ + ''' + out = "\t{0}\n\t".format( self.regen_str() ) + + # Place a ^ character at the given locations + curpos = 1 + for pos in sorted( pos_list ): + # Pad spaces, then add a ^ + out += ' ' * (pos - curpos) + out += '^' + curpos += pos + + return out + + def rparam_start( self ): + ''' + Starting positing char of rparam_token in a regen_str + ''' + return len( self.lparam_token.value ) + len( self.operator_token.value ) + + def __repr__( self ): + # Build string representation based off of what has been set + # lparam, operator and rparam are always set + out = "Expression: {0}{1}{2}".format( + self.lparam_token.value, + self.operator_token.value, + self.rparam_token.value, + ) + + # TODO - Add more depending on what has been set + return out + + def unique_keys( self ): + ''' + Generates a list of unique identifiers for the expression that is mergeable + with other functional equivalent expressions. + + This method should never get called directly as a generic Expression + ''' + return [ ('UNKNOWN KEY', 'UNKNOWN EXPRESSION') ] + + +class AssignmentExpression( Expression ): + ''' + Container class for assignment KLL expressions + ''' + type = None + name = None + pos = None + value = None + + ## Setters ## + def array( self, name, pos, value ): + ''' + Assign array assignment parameters to expression + + @param name: Name of variable + @param pos: Array position of the value (if None, overwrite the entire array) + @param value: Value of the array, if pos is specified, this is the value of an element + + @return: True if parsing was successful + ''' + self.type = 'Array' + self.name = name + self.pos = pos + self.value = value + + # If pos is not none, flatten + if pos is not None: + self.value = "".join( str( x ) for x in self.value ) + + return True + + def variable( self, name, value ): + ''' + Assign variable assignment parameters to expression + + @param name: Name of variable + @param value: Value of variable + + @return: True if parsing was successful + ''' + self.type = 'Variable' + self.name = name + self.value = value + + # Flatten value, often a list of various token types + self.value = "".join( str( x ) for x in self.value ) + + return True + + def __repr__( self ): + if self.type == 'Variable': + return "{0} = {1};".format( self.name, self.value ) + elif self.type == 'Array': + return "{0}[{1}] = {2};".format( self.name, self.pos, self.value ) + + return "ASSIGNMENT UNKNOWN" + + def unique_keys( self ): + ''' + Generates a list of unique identifiers for the expression that is mergeable + with other functional equivalent expressions. + ''' + return [ ( self.name, self ) ] + + +class NameAssociationExpression( Expression ): + ''' + Container class for name association KLL expressions + ''' + type = None + name = None + association = None + + ## Setters ## + def capability( self, name, association, parameters ): + ''' + Assign a capability C function name association + + @param name: Name of capability + @param association: Name of capability in target backend output + + @return: True if parsing was successful + ''' + self.type = 'Capability' + self.name = name + self.association = CapId( association, 'Definition', parameters ) + + return True + + def define( self, name, association ): + ''' + Assign a define C define name association + + @param name: Name of variable + @param association: Name of association in target backend output + + @return: True if parsing was successful + ''' + self.type = 'Define' + self.name = name + self.association = association + + return True + + def __repr__( self ): + return "{0} <= {1};".format( self.name, self.association ) + + def unique_keys( self ): + ''' + Generates a list of unique identifiers for the expression that is mergeable + with other functional equivalent expressions. + ''' + return [ ( self.name, self ) ] + + +class DataAssociationExpression( Expression ): + ''' + Container class for data association KLL expressions + ''' + type = None + association = None + value = None + + ## Setters ## + def animation( self, animations, animation_modifiers ): + ''' + Animation definition and configuration + + @return: True if parsing was successful + ''' + self.type = 'Animation' + self.association = animations + self.value = animation_modifiers + + return True + + def animationFrame( self, animation_frames, pixel_modifiers ): + ''' + Pixel composition of an Animation Frame + + @return: True if parsing was successful + ''' + + self.type = 'AnimationFrame' + self.association = animation_frames + self.value = pixel_modifiers + + return True + + def pixelPosition( self, pixels, position ): + ''' + Pixel Positioning + + @return: True if parsing was successful + ''' + for pixel in pixels: + pixel.setPosition( position ) + + self.type = 'PixelPosition' + self.association = pixels + + return True + + def scanCodePosition( self, scancodes, position ): + ''' + Scan Code to Position Mapping + + Note: Accepts lists of scan codes + Alone this isn't useful, but you can assign rows and columns using ranges instead of individually + + @return: True if parsing was successful + ''' + for scancode in scancodes: + scancode.setPosition( position ) + + self.type = 'ScanCodePosition' + self.association = scancodes + + return True + + def __repr__( self ): + if self.type in ['PixelPosition', 'ScanCodePosition']: + output = "" + for index, association in enumerate( self.association ): + if index > 0: + output += "; " + output += "{0}".format( association ) + return "{0};".format( output ) + return "{0} <= {1};".format( self.association, self.value ) + + def unique_keys( self ): + ''' + Generates a list of unique identifiers for the expression that is mergeable + with other functional equivalent expressions. + ''' + keys = [] + + # Positions require a bit more introspection to get the unique keys + if self.type in ['PixelPosition', 'ScanCodePosition']: + for index, key in enumerate( self.association ): + uniq_expr = self + + # If there is more than one key, copy the expression + # and remove the non-related variants + if len( self.association ) > 1: + uniq_expr = copy.copy( self ) + + # Isolate variant by index + uniq_expr.association = [ uniq_expr.association[ index ] ] + + keys.append( ( "{0}".format( key.unique_key() ), uniq_expr ) ) + + # AnimationFrames are already list of keys + # TODO Reorder frame assignments to dedup function equivalent mappings + elif self.type in ['AnimationFrame']: + for index, key in enumerate( self.association ): + uniq_expr = self + + # If there is more than one key, copy the expression + # and remove the non-related variants + if len( self.association ) > 1: + uniq_expr = copy.copy( self ) + + # Isolate variant by index + uniq_expr.association = [ uniq_expr.association[ index ] ] + + keys.append( ( "{0}".format( key ), uniq_expr ) ) + + # Otherwise treat as a single element + else: + keys = [ ( "{0}".format( self.association ), self ) ] + + # Remove any duplicate keys + # TODO Stat? Might be at neat report about how many duplicates were squashed + keys = list( set( keys ) ) + + return keys + + +class MapExpression( Expression ): + ''' + Container class for KLL map expressions + ''' + type = None + triggers = None + operator = None + results = None + animation = None + animation_frame = None + pixels = None + position = None + + ## Setters ## + def scanCode( self, triggers, operator, results ): + ''' + Scan Code mapping + + @param triggers: Sequence of combos of ranges of namedtuples + @param operator: Type of map operation + @param results: Sequence of combos of ranges of namedtuples + + @return: True if parsing was successful + ''' + self.type = 'ScanCode' + self.triggers = triggers + self.operator = operator + self.results = results + + return True + + def usbCode( self, triggers, operator, results ): + ''' + USB Code mapping + + @param triggers: Sequence of combos of ranges of namedtuples + @param operator: Type of map operation + @param results: Sequence of combos of ranges of namedtuples + + @return: True if parsing was successful + ''' + self.type = 'USBCode' + self.triggers = triggers + self.operator = operator + self.results = results + + return True + + def animationTrigger( self, animation, operator, results ): + ''' + Animation Trigger mapping + + @param animation: Animation trigger of result + @param operator: Type of map operation + @param results: Sequence of combos of ranges of namedtuples + + @return: True if parsing was successful + ''' + self.type = 'Animation' + self.animation = animation + self.triggers = animation + self.operator = operator + self.results = results + + return True + + def pixelChannels( self, pixelmap, trigger ): + ''' + Pixel Channel Composition + + @return: True if parsing was successful + ''' + self.type = 'PixelChannel' + self.pixel = pixelmap + self.position = trigger + + return True + + def sequencesOfCombosOfIds( self, expression_param ): + ''' + Prettified Sequence of Combos of Identifiers + + @param expression_param: Trigger or Result parameter of an expression + + Scan Code Example + [[[S10, S16], [S42]], [[S11, S16], [S42]]] -> (S10 + S16, S42)|(S11 + S16, S42) + ''' + output = "" + + # Sometimes during error cases, might be None + if expression_param is None: + return output + + # Iterate over each trigger/result variants (expanded from ranges), each one is a sequence + for index, sequence in enumerate( expression_param ): + if index > 0: + output += "|" + output += "(" + + # Iterate over each combo (element of the sequence) + for index, combo in enumerate( sequence ): + if index > 0: + output += ", " + + # Iterate over each trigger identifier + for index, identifier in enumerate( combo ): + if index > 0: + output += " + " + output += "{0}".format( identifier ) + + output += ")" + + return output + + def elems( self ): + ''' + Return number of trigger and result elements + + Useful for determining if this is a trigger macro (2+) + Should always return at least (1,1) unless it's an invalid calculation + + @return: ( triggers, results ) + ''' + elems = [ 0, 0 ] + + # XXX Needed? + if self.type == 'PixelChannel': + return tuple( elems ) + + # Iterate over each trigger variant (expanded from ranges), each one is a sequence + for sequence in self.triggers: + # Iterate over each combo (element of the sequence) + for combo in sequence: + # Just measure the size of the combo + elems[0] += len( combo ) + + # Iterate over each result variant (expanded from ranges), each one is a sequence + for sequence in self.results: + # Iterate over each combo (element of the sequence) + for combo in sequence: + # Just measure the size of the combo + elems[1] += len( combo ) + + return tuple( elems ) + + def trigger_str( self ): + ''' + String version of the trigger + Used for sorting + ''' + # Pixel Channel Mapping doesn't follow the same pattern + if self.type == 'PixelChannel': + return "{0}".format( self.pixel ) + + return "{0}".format( + self.sequencesOfCombosOfIds( self.triggers ), + ) + + def result_str( self ): + ''' + String version of the result + Used for sorting + ''' + # Pixel Channel Mapping doesn't follow the same pattern + if self.type == 'PixelChannel': + return "{0}".format( self.position ) + + return "{0}".format( + self.sequencesOfCombosOfIds( self.results ), + ) + + def __repr__( self ): + # Pixel Channel Mapping doesn't follow the same pattern + if self.type == 'PixelChannel': + return "{0} : {1};".format( self.pixel, self.position ) + + return "{0} {1} {2};".format( + self.sequencesOfCombosOfIds( self.triggers ), + self.operator, + self.sequencesOfCombosOfIds( self.results ), + ) + + def unique_keys( self ): + ''' + Generates a list of unique identifiers for the expression that is mergeable + with other functional equivalent expressions. + + TODO: This function should re-order combinations to generate the key. + The final generated combo will be in the original order. + ''' + keys = [] + + # Pixel Channel only has key per mapping + if self.type == 'PixelChannel': + keys = [ ( "{0}".format( self.pixel ), self ) ] + + # Split up each of the keys + else: + # Iterate over each trigger/result variants (expanded from ranges), each one is a sequence + for index, sequence in enumerate( self.triggers ): + key = "" + uniq_expr = self + + # If there is more than one key, copy the expression + # and remove the non-related variants + if len( self.triggers ) > 1: + uniq_expr = copy.copy( self ) + + # Isolate variant by index + uniq_expr.triggers = [ uniq_expr.triggers[ index ] ] + + # Iterate over each combo (element of the sequence) + for index, combo in enumerate( sequence ): + if index > 0: + key += ", " + + # Iterate over each trigger identifier + for index, identifier in enumerate( combo ): + if index > 0: + key += " + " + key += "{0}".format( identifier ) + + # Add key to list + keys.append( ( key, uniq_expr ) ) + + # Remove any duplicate keys + # TODO Stat? Might be at neat report about how many duplicates were squashed + keys = list( set( keys ) ) + + return keys + diff --git a/common/file.py b/common/file.py new file mode 100644 index 0000000..8450f90 --- /dev/null +++ b/common/file.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +''' +KLL File Container +''' + +# Copyright (C) 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 . + +### Imports ### + +import os + +import common.context as context + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +class KLLFile: + ''' + Container class for imported KLL files + ''' + def __init__( self, path, file_context ): + ''' + Initialize file container + + @param path: Path to filename, if relative, relative to the execution environment + @param context: KLL Context object + ''' + self.path = path + self.context = file_context + self.lines = [] + self.data = "" + + def __repr__( self ): + context_str = type( self.context ).__name__ + + # Show layer info if this is a PartialMap + if isinstance( self.context, context.PartialMapContext ): + context_str = "{0}({1})".format( context_str, self.context.layer ) + + return "({0}, {1})".format( self.path, context_str ) + + def check( self ): + ''' + Make sure that the file exists at the initialized path + ''' + exists = os.path.isfile( self.path ) + + # Display error message, will exit later + if not exists: + print( "{0} {1} does not exist...".format( ERROR, self.path ) ) + + return exists + + def read( self ): + ''' + Read the contents of the file path into memory + Reads both per line and complete copies + ''' + try: + # Read file into memory, removing newlines + with open( self.path ) as f: + self.data = f.read() + self.lines = self.data.splitlines() + + except: + print( "{0} Failed to read '{1}' into memory...".format( ERROR, self.path ) ) + return False + + return True + + + diff --git a/common/hid_dict.py b/common/hid_dict.py new file mode 100644 index 0000000..d9e5b7f --- /dev/null +++ b/common/hid_dict.py @@ -0,0 +1,1583 @@ +#!/usr/bin/env python3 +''' +KLL Compiler - HID Dictionary Lookup + +USB Code Lookup Dictionary +''' + +# 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 . + +# Rather than generating tables of hex USB codes for the keymapping tables, +# readable defines are used (which correspond to usb_hid.h) +hid_lookup_dictionary = dict([ + # Fall-through block + ( ('NONE', 0), '' ), # Special case, there are no arguments + + # USB HID Keyboard Codes + ( ('USB', 0x00), 'KEY_NOEVENT' ), # Event, not a physical key + ( ('USB', 0x01), 'KEY_ERRORROLLOVER' ), # Event, not a physical key + ( ('USB', 0x02), 'KEY_POSTFAIL' ), # Event, not a physical key + ( ('USB', 0x03), 'KEY_ERRORUNDEFINED' ), # Event, not a physical key + ( ('USB', 0x04), 'KEY_A' ), + ( ('USB', 0x05), 'KEY_B' ), + ( ('USB', 0x06), 'KEY_C' ), + ( ('USB', 0x07), 'KEY_D' ), + ( ('USB', 0x08), 'KEY_E' ), + ( ('USB', 0x09), 'KEY_F' ), + ( ('USB', 0x0A), 'KEY_G' ), + ( ('USB', 0x0B), 'KEY_H' ), + ( ('USB', 0x0C), 'KEY_I' ), + ( ('USB', 0x0D), 'KEY_J' ), + ( ('USB', 0x0E), 'KEY_K' ), + ( ('USB', 0x0F), 'KEY_L' ), + ( ('USB', 0x10), 'KEY_M' ), + ( ('USB', 0x11), 'KEY_N' ), + ( ('USB', 0x12), 'KEY_O' ), + ( ('USB', 0x13), 'KEY_P' ), + ( ('USB', 0x14), 'KEY_Q' ), + ( ('USB', 0x15), 'KEY_R' ), + ( ('USB', 0x16), 'KEY_S' ), + ( ('USB', 0x17), 'KEY_T' ), + ( ('USB', 0x18), 'KEY_U' ), + ( ('USB', 0x19), 'KEY_V' ), + ( ('USB', 0x1A), 'KEY_W' ), + ( ('USB', 0x1B), 'KEY_X' ), + ( ('USB', 0x1C), 'KEY_Y' ), + ( ('USB', 0x1D), 'KEY_Z' ), + ( ('USB', 0x1E), 'KEY_1' ), + ( ('USB', 0x1F), 'KEY_2' ), + ( ('USB', 0x20), 'KEY_3' ), + ( ('USB', 0x21), 'KEY_4' ), + ( ('USB', 0x22), 'KEY_5' ), + ( ('USB', 0x23), 'KEY_6' ), + ( ('USB', 0x24), 'KEY_7' ), + ( ('USB', 0x25), 'KEY_8' ), + ( ('USB', 0x26), 'KEY_9' ), + ( ('USB', 0x27), 'KEY_0' ), + ( ('USB', 0x28), 'KEY_ENTER' ), + ( ('USB', 0x29), 'KEY_ESC' ), + ( ('USB', 0x2A), 'KEY_BACKSPACE' ), + ( ('USB', 0x2B), 'KEY_TAB' ), + ( ('USB', 0x2C), 'KEY_SPACE' ), + ( ('USB', 0x2D), 'KEY_MINUS' ), + ( ('USB', 0x2E), 'KEY_EQUAL' ), + ( ('USB', 0x2F), 'KEY_LEFT_BRACKET' ), + ( ('USB', 0x30), 'KEY_RIGHT_BRACKET' ), + ( ('USB', 0x31), 'KEY_BACKSLASH' ), + ( ('USB', 0x32), 'KEY_NUMBER' ), + ( ('USB', 0x33), 'KEY_SEMICOLON' ), + ( ('USB', 0x34), 'KEY_QUOTE' ), + ( ('USB', 0x35), 'KEY_BACKTICK' ), + ( ('USB', 0x36), 'KEY_COMMA' ), + ( ('USB', 0x37), 'KEY_PERIOD' ), + ( ('USB', 0x38), 'KEY_SLASH' ), + ( ('USB', 0x39), 'KEY_CAPS_LOCK' ), + ( ('USB', 0x3A), 'KEY_F1' ), + ( ('USB', 0x3B), 'KEY_F2' ), + ( ('USB', 0x3C), 'KEY_F3' ), + ( ('USB', 0x3D), 'KEY_F4' ), + ( ('USB', 0x3E), 'KEY_F5' ), + ( ('USB', 0x3F), 'KEY_F6' ), + ( ('USB', 0x40), 'KEY_F7' ), + ( ('USB', 0x41), 'KEY_F8' ), + ( ('USB', 0x42), 'KEY_F9' ), + ( ('USB', 0x43), 'KEY_F10' ), + ( ('USB', 0x44), 'KEY_F11' ), + ( ('USB', 0x45), 'KEY_F12' ), + ( ('USB', 0x46), 'KEY_PRINTSCREEN' ), + ( ('USB', 0x47), 'KEY_SCROLL_LOCK' ), + ( ('USB', 0x48), 'KEY_PAUSE' ), + ( ('USB', 0x49), 'KEY_INSERT' ), + ( ('USB', 0x4A), 'KEY_HOME' ), + ( ('USB', 0x4B), 'KEY_PAGE_UP' ), + ( ('USB', 0x4C), 'KEY_DELETE' ), + ( ('USB', 0x4D), 'KEY_END' ), + ( ('USB', 0x4E), 'KEY_PAGE_DOWN' ), + ( ('USB', 0x4F), 'KEY_RIGHT' ), + ( ('USB', 0x50), 'KEY_LEFT' ), + ( ('USB', 0x51), 'KEY_DOWN' ), + ( ('USB', 0x52), 'KEY_UP' ), + ( ('USB', 0x53), 'KEY_NUM_LOCK' ), + ( ('USB', 0x54), 'KEYPAD_SLASH' ), + ( ('USB', 0x55), 'KEYPAD_ASTERISK' ), + ( ('USB', 0x56), 'KEYPAD_MINUS' ), + ( ('USB', 0x57), 'KEYPAD_PLUS' ), + ( ('USB', 0x58), 'KEYPAD_ENTER' ), + ( ('USB', 0x59), 'KEYPAD_1' ), + ( ('USB', 0x5A), 'KEYPAD_2' ), + ( ('USB', 0x5B), 'KEYPAD_3' ), + ( ('USB', 0x5C), 'KEYPAD_4' ), + ( ('USB', 0x5D), 'KEYPAD_5' ), + ( ('USB', 0x5E), 'KEYPAD_6' ), + ( ('USB', 0x5F), 'KEYPAD_7' ), + ( ('USB', 0x60), 'KEYPAD_8' ), + ( ('USB', 0x61), 'KEYPAD_9' ), + ( ('USB', 0x62), 'KEYPAD_0' ), + ( ('USB', 0x63), 'KEYPAD_PERIOD' ), + ( ('USB', 0x64), 'KEY_ISO_SLASH' ), + ( ('USB', 0x65), 'KEY_APP' ), + ( ('USB', 0x66), 'KEYBOARD_STATUS' ), # Used for indicating status or errors, not a key + ( ('USB', 0x67), 'KEYPAD_EQUAL' ), + ( ('USB', 0x68), 'KEY_F13' ), + ( ('USB', 0x69), 'KEY_F14' ), + ( ('USB', 0x6A), 'KEY_F15' ), + ( ('USB', 0x6B), 'KEY_F16' ), + ( ('USB', 0x6C), 'KEY_F17' ), + ( ('USB', 0x6D), 'KEY_F18' ), + ( ('USB', 0x6E), 'KEY_F19' ), + ( ('USB', 0x6F), 'KEY_F20' ), + ( ('USB', 0x70), 'KEY_F21' ), + ( ('USB', 0x71), 'KEY_F22' ), + ( ('USB', 0x72), 'KEY_F23' ), + ( ('USB', 0x73), 'KEY_F24' ), + ( ('USB', 0x74), 'KEY_EXEC' ), + ( ('USB', 0x75), 'KEY_HELP' ), + ( ('USB', 0x76), 'KEY_MENU' ), + ( ('USB', 0x77), 'KEY_SELECT' ), + ( ('USB', 0x78), 'KEY_STOP' ), + ( ('USB', 0x79), 'KEY_AGAIN' ), + ( ('USB', 0x7A), 'KEY_UNDO' ), + ( ('USB', 0x7B), 'KEY_CUT' ), + ( ('USB', 0x7C), 'KEY_COPY' ), + ( ('USB', 0x7D), 'KEY_PASTE' ), + ( ('USB', 0x7E), 'KEY_FIND' ), + ( ('USB', 0x7F), 'KEY_MUTE' ), + ( ('USB', 0x80), 'KEY_VOL_UP' ), + ( ('USB', 0x81), 'KEY_VOL_DOWN' ), + ( ('USB', 0x82), 'KEY_CAPS_TLOCK' ), # Toggle "Locking" Scroll Lock (Old keyboards with Locking Caps Lock) + ( ('USB', 0x83), 'KEY_NUM_TLOCK' ), + ( ('USB', 0x84), 'KEY_SCROLL_TLOCK' ), + ( ('USB', 0x85), 'KEYPAD_COMMA' ), # Brazillian (See spec) + ( ('USB', 0x86), 'KEYPAD_EQUAL_AS' ), # AS/400 Keyboard (See spec) + ( ('USB', 0x87), 'KEY_INTER1' ), # KANJI1 - Brazillian and Japanese "Ru" and "-" + ( ('USB', 0x88), 'KEY_INTER2' ), # KANJI2 - Japanese Katakana/Hiragana + ( ('USB', 0x89), 'KEY_INTER3' ), # KANJI3 - Japanese Yen + ( ('USB', 0x8A), 'KEY_INTER4' ), # KANJI4 - Japanese Henkan + ( ('USB', 0x8B), 'KEY_INTER5' ), # KANJI5 - Japanese Muhenkan + ( ('USB', 0x8C), 'KEY_INTER6' ), # KANJI6 - PC('USB', 0x62) Comma (Ka-m-ma) + ( ('USB', 0x8D), 'KEY_INTER7' ), # KANJI7 - Double-Byte/Single-Byte Toggle + ( ('USB', 0x8E), 'KEY_INTER8' ), # KANJI8 - Undefined + ( ('USB', 0x8F), 'KEY_INTER9' ), # KANJI9 - Undefined + ( ('USB', 0x90), 'KEY_LANG1' ), # Korean Hangul/English Toggle + ( ('USB', 0x91), 'KEY_LANG2' ), # Korean Hanja Conversion - Japanese Eisu + ( ('USB', 0x92), 'KEY_LANG3' ), # Japanese Katakana Key (USB) + ( ('USB', 0x93), 'KEY_LANG4' ), # Japanese Hiragana Key (USB) + ( ('USB', 0x94), 'KEY_LANG5' ), # Japanese Zenkaku/Hankaku Key (USB) + ( ('USB', 0x95), 'KEY_LANG6' ), # Reserved (Application Specific) + ( ('USB', 0x96), 'KEY_LANG7' ), # Reserved (Application Specific) + ( ('USB', 0x97), 'KEY_LANG8' ), # Reserved (Application Specific) + ( ('USB', 0x98), 'KEY_LANG9' ), # Reserved (Application Specific) + ( ('USB', 0x99), 'KEY_ALT_ERASE' ), # Special Erase (See Spec) + ( ('USB', 0x9A), 'KEY_SYSREQ_ATT' ), # Modifier Type + ( ('USB', 0x9B), 'KEY_CANCEL' ), + ( ('USB', 0x9C), 'KEY_CLEAR' ), + ( ('USB', 0x9D), 'KEY_PRIOR' ), + ( ('USB', 0x9E), 'KEY_RETURN' ), + ( ('USB', 0x9F), 'KEY_SEPARATOR' ), + ( ('USB', 0xA0), 'KEY_OUT' ), + ( ('USB', 0xA1), 'KEY_OPER' ), + ( ('USB', 0xA2), 'KEY_CLEAR_AGAIN' ), + ( ('USB', 0xA3), 'KEY_CRSEL_PROPS' ), + ( ('USB', 0xA4), 'KEY_EXSEL' ), +# ('USB', 0xA5) - ('USB', 0xAF) Reserved + ( ('USB', 0xB0), 'KEYPAD_00' ), + ( ('USB', 0xB1), 'KEYPAD_000' ), + ( ('USB', 0xB2), 'KEY_1000_SEP' ), + ( ('USB', 0xB3), 'KEY_DECIMAL_SEP' ), + ( ('USB', 0xB4), 'KEY_CURRENCY_MAIN' ), + ( ('USB', 0xB5), 'KEY_CURRENCY_SUB' ), + ( ('USB', 0xB6), 'KEYPAD_LPAREN' ), + ( ('USB', 0xB7), 'KEYPAD_RPAREN' ), + ( ('USB', 0xB8), 'KEYPAD_LBRACKET' ), + ( ('USB', 0xB9), 'KEYPAD_RBRACKET' ), + ( ('USB', 0xBA), 'KEYPAD_TAB' ), + ( ('USB', 0xBB), 'KEYPAD_BACKSPACE' ), + ( ('USB', 0xBC), 'KEYPAD_A' ), + ( ('USB', 0xBD), 'KEYPAD_B' ), + ( ('USB', 0xBE), 'KEYPAD_C' ), + ( ('USB', 0xBF), 'KEYPAD_D' ), + ( ('USB', 0xC0), 'KEYPAD_E' ), + ( ('USB', 0xC1), 'KEYPAD_F' ), + ( ('USB', 0xC2), 'KEYPAD_XOR' ), + ( ('USB', 0xC3), 'KEYPAD_CHEVRON' ), + ( ('USB', 0xC4), 'KEYPAD_PERCENT' ), + ( ('USB', 0xC5), 'KEYPAD_LTHAN' ), + ( ('USB', 0xC6), 'KEYPAD_GTHAN' ), + ( ('USB', 0xC7), 'KEYPAD_BITAND' ), + ( ('USB', 0xC8), 'KEYPAD_AND' ), + ( ('USB', 0xC9), 'KEYPAD_BITOR' ), + ( ('USB', 0xCA), 'KEYPAD_OR' ), + ( ('USB', 0xCB), 'KEYPAD_COLON' ), + ( ('USB', 0xCC), 'KEYPAD_POUND' ), + ( ('USB', 0xCD), 'KEYPAD_SPACE' ), + ( ('USB', 0xCE), 'KEYPAD_AT' ), + ( ('USB', 0xCF), 'KEYPAD_EXCLAIM' ), + ( ('USB', 0xD0), 'KEYPAD_MEM_STORE' ), + ( ('USB', 0xD1), 'KEYPAD_MEM_RECALL' ), + ( ('USB', 0xD2), 'KEYPAD_MEM_CLEAR' ), + ( ('USB', 0xD3), 'KEYPAD_MEM_ADD' ), + ( ('USB', 0xD4), 'KEYPAD_MEM_SUB' ), + ( ('USB', 0xD5), 'KEYPAD_MEM_MULT' ), + ( ('USB', 0xD6), 'KEYPAD_MEM_DIV' ), + ( ('USB', 0xD7), 'KEYPAD_PLUS_MINUS' ), + ( ('USB', 0xD8), 'KEYPAD_CLEAR' ), + ( ('USB', 0xD9), 'KEYPAD_CLEAR_ENTRY' ), + ( ('USB', 0xDA), 'KEYPAD_BINARY' ), + ( ('USB', 0xDB), 'KEYPAD_OCTAL' ), + ( ('USB', 0xDC), 'KEYPAD_DECIMAL' ), + ( ('USB', 0xDD), 'KEYPAD_HEX' ), +# ('USB', 0xDE) - ('USB', 0xDF) Reserved + ( ('USB', 0xE0), 'KEY_LCTRL' ), + ( ('USB', 0xE1), 'KEY_LSHIFT' ), + ( ('USB', 0xE2), 'KEY_LALT' ), + ( ('USB', 0xE3), 'KEY_LGUI' ), + ( ('USB', 0xE4), 'KEY_RCTRL' ), + ( ('USB', 0xE5), 'KEY_RSHIFT' ), + ( ('USB', 0xE6), 'KEY_RALT' ), + ( ('USB', 0xE7), 'KEY_RGUI' ), +# ('USB', 0xE8) - ('USB', 0xFF)FF Reserved, using ('USB', 0xF0) to ('USB', 0xFF) for function key placeholders + ( ('USB', 0xF0), 'KEY_FUN1' ), + ( ('USB', 0xF1), 'KEY_FUN2' ), + ( ('USB', 0xF2), 'KEY_FUN3' ), + ( ('USB', 0xF3), 'KEY_FUN4' ), + ( ('USB', 0xF4), 'KEY_FUN5' ), + ( ('USB', 0xF5), 'KEY_FUN6' ), + ( ('USB', 0xF6), 'KEY_FUN7' ), + ( ('USB', 0xF7), 'KEY_FUN8' ), + ( ('USB', 0xF8), 'KEY_FUN9' ), + ( ('USB', 0xF9), 'KEY_FUN10' ), + ( ('USB', 0xFA), 'KEY_FUN11' ), + ( ('USB', 0xFB), 'KEY_FUN12' ), + ( ('USB', 0xFC), 'KEY_FUN13' ), + ( ('USB', 0xFD), 'KEY_FUN14' ), + ( ('USB', 0xFE), 'KEY_FUN15' ), + ( ('USB', 0xFF), 'KEY_FUN16' ), +# ('USB', 0x100) to ('USB', 0x121) for function key placeholders, not valid usb codes (must use a translation .kll file before firmware compilation) + ( ('USB', 0x100), 'KEY_LCK1' ), + ( ('USB', 0x101), 'KEY_LCK2' ), + ( ('USB', 0x102), 'KEY_LCK3' ), + ( ('USB', 0x103), 'KEY_LCK4' ), + ( ('USB', 0x104), 'KEY_LCK5' ), + ( ('USB', 0x105), 'KEY_LCK6' ), + ( ('USB', 0x106), 'KEY_LCK7' ), + ( ('USB', 0x107), 'KEY_LCK8' ), + ( ('USB', 0x108), 'KEY_LCK9' ), + ( ('USB', 0x109), 'KEY_LCK10' ), + ( ('USB', 0x10A), 'KEY_LCK11' ), + ( ('USB', 0x10B), 'KEY_LCK12' ), + ( ('USB', 0x10C), 'KEY_LCK13' ), + ( ('USB', 0x10D), 'KEY_LCK14' ), + ( ('USB', 0x10E), 'KEY_LCK15' ), + ( ('USB', 0x10F), 'KEY_LCK16' ), + ( ('USB', 0x110), 'KEY_LAT1' ), + ( ('USB', 0x111), 'KEY_LAT2' ), + ( ('USB', 0x112), 'KEY_LAT3' ), + ( ('USB', 0x113), 'KEY_LAT4' ), + ( ('USB', 0x114), 'KEY_LAT5' ), + ( ('USB', 0x115), 'KEY_LAT6' ), + ( ('USB', 0x116), 'KEY_LAT7' ), + ( ('USB', 0x117), 'KEY_LAT8' ), + ( ('USB', 0x118), 'KEY_LAT9' ), + ( ('USB', 0x119), 'KEY_LAT10' ), + ( ('USB', 0x11A), 'KEY_LAT11' ), + ( ('USB', 0x11B), 'KEY_LAT12' ), + ( ('USB', 0x11C), 'KEY_LAT13' ), + ( ('USB', 0x11D), 'KEY_LAT14' ), + ( ('USB', 0x11E), 'KEY_LAT15' ), + ( ('USB', 0x11F), 'KEY_LAT16' ), + ( ('USB', 0x120), 'KEY_NEXT_LAYER' ), + ( ('USB', 0x121), 'KEY_PREV_LAYER' ), + + # USB HID Consumer Control Codes +# List of Consumer Codes - USB HID 1.12v2 +# Only listing relevant ones, let me know if you need more -HaaTa +# NKRO HID Supports 0x020 - 0x29C + ( ('CONS', 0x020), 'CONSUMER_10' ), + ( ('CONS', 0x021), 'CONSUMER_100' ), + ( ('CONS', 0x022), 'CONSUMER_AM_PM' ), +# 0x023 - 0x03F Reserved + ( ('CONS', 0x030), 'CONSUMER_POWER' ), + ( ('CONS', 0x031), 'CONSUMER_RESET' ), + ( ('CONS', 0x032), 'CONSUMER_SLEEP' ), + ( ('CONS', 0x033), 'CONSUMER_SLEEP_AFTER' ), + ( ('CONS', 0x034), 'CONSUMER_SLEEP_MODE' ), + ( ('CONS', 0x035), 'CONSUMER_ILLUMINATION' ), + +# 0x037 - 0x03F Reserved + ( ('CONS', 0x040), 'CONSUMER_MENU' ), + ( ('CONS', 0x041), 'CONSUMER_MENU_PICK' ), + ( ('CONS', 0x042), 'CONSUMER_MENU_UP' ), + ( ('CONS', 0x043), 'CONSUMER_MENU_DOWN' ), + ( ('CONS', 0x044), 'CONSUMER_MENU_LEFT' ), + ( ('CONS', 0x045), 'CONSUMER_MENU_RIGHT' ), + ( ('CONS', 0x046), 'CONSUMER_MENU_ESCAPE' ), + ( ('CONS', 0x047), 'CONSUMER_MENU_VALUE_INCREASE' ), + ( ('CONS', 0x048), 'CONSUMER_MENU_VALUE_DECREASE' ), +# 0x049 - 0x05F Reserved + ( ('CONS', 0x060), 'CONSUMER_DATA_ON_SCREEN' ), + ( ('CONS', 0x061), 'CONSUMER_CLOSED_CAPTION' ), + ( ('CONS', 0x062), 'CONSUMER_CLOSED_CAPTION_SELECT' ), + ( ('CONS', 0x063), 'CONSUMER_VCR_TV' ), + ( ('CONS', 0x064), 'CONSUMER_BROADCAST_MODE' ), + ( ('CONS', 0x065), 'CONSUMER_SNAPSHOT' ), + ( ('CONS', 0x066), 'CONSUMER_STILL' ), +# 0x067 - 0x06E Reserved? + ( ('CONS', 0x06F), 'CONSUMER_BRIGHTNESS_INCREMENT' ), + ( ('CONS', 0x070), 'CONSUMER_BRIGHTNESS_DECREMENT' ), + + ( ('CONS', 0x072), 'CONSUMER_BACKLIGHT_TOGGLE' ), + ( ('CONS', 0x073), 'CONSUMER_BRIGHTNESS_MIN' ), + ( ('CONS', 0x074), 'CONSUMER_BRIGHTNESS_MAX' ), + ( ('CONS', 0x075), 'CONSUMER_BRIGHTNESS_AUTO' ), +# 0x076 - 0x07F Reserved + + ( ('CONS', 0x081), 'CONSUMER_ASSIGN_SELECTION' ), + ( ('CONS', 0x082), 'CONSUMER_MODE_STEP' ), + ( ('CONS', 0x083), 'CONSUMER_RECALL_LAST' ), + ( ('CONS', 0x084), 'CONSUMER_ENTER_CHANNEL' ), + ( ('CONS', 0x085), 'CONSUMER_ORDER_MOVIE' ), + + ( ('CONS', 0x088), 'CONSUMER_MEDIA_COMPUTER' ), + ( ('CONS', 0x089), 'CONSUMER_MEDIA_TV' ), + ( ('CONS', 0x08A), 'CONSUMER_MEDIA_WWW' ), + ( ('CONS', 0x08B), 'CONSUMER_MEDIA_DVD' ), + ( ('CONS', 0x08C), 'CONSUMER_MEDIA_TELEPHONE' ), + ( ('CONS', 0x08D), 'CONSUMER_MEDIA_PROGRAM_GUIDE' ), + ( ('CONS', 0x08E), 'CONSUMER_MEDIA_VIDEO_PHONE' ), + ( ('CONS', 0x08F), 'CONSUMER_MEDIA_SELECT_GAMES' ), + ( ('CONS', 0x090), 'CONSUMER_MEDIA_SELECT_MESSAGES' ), + ( ('CONS', 0x091), 'CONSUMER_MEDIA_SELECT_CD' ), + ( ('CONS', 0x092), 'CONSUMER_MEDIA_SELECT_VCR' ), + ( ('CONS', 0x093), 'CONSUMER_MEDIA_SELECT_TUNER' ), + ( ('CONS', 0x094), 'CONSUMER_QUIT' ), + ( ('CONS', 0x095), 'CONSUMER_HELP' ), + ( ('CONS', 0x096), 'CONSUMER_MEDIA_SELECT_TAPE' ), + ( ('CONS', 0x097), 'CONSUMER_MEDIA_SELECT_CABLE' ), + ( ('CONS', 0x098), 'CONSUMER_MEDIA_SELECT_SATELLITE' ), + ( ('CONS', 0x099), 'CONSUMER_MEDIA_SELECT_SECURITY' ), + ( ('CONS', 0x09A), 'CONSUMER_MEDIA_SELECT_HOME' ), + ( ('CONS', 0x09B), 'CONSUMER_MEDIA_SELECT_CALL' ), + ( ('CONS', 0x09C), 'CONSUMER_CHANNEL_INCREMENT' ), + ( ('CONS', 0x09D), 'CONSUMER_CAHNNEL_DECREMENT' ), + ( ('CONS', 0x09E), 'CONSUMER_MEDIA_SELECT_SAP' ), +# 0x09F Reserved + ( ('CONS', 0x0A0), 'CONSUMER_VCR_PLUS' ), + ( ('CONS', 0x0A1), 'CONSUMER_ONCE' ), + ( ('CONS', 0x0A2), 'CONSUMER_DAILY' ), + ( ('CONS', 0x0A3), 'CONSUMER_WEEKLY' ), + ( ('CONS', 0x0A4), 'CONSUMER_MONTHLY' ), +# 0x0A5 - 0x0AF Reserved + ( ('CONS', 0x0B0), 'CONSUMER_PLAY' ), + ( ('CONS', 0x0B1), 'CONSUMER_PAUSE' ), + ( ('CONS', 0x0B2), 'CONSUMER_RECORD' ), + ( ('CONS', 0x0B3), 'CONSUMER_FAST_FORWARD' ), + ( ('CONS', 0x0B4), 'CONSUMER_REWIND' ), + ( ('CONS', 0x0B5), 'CONSUMER_SCAN_NEXT_TRACK' ), + ( ('CONS', 0x0B6), 'CONSUMER_SCAN_PREVIOUS_TRACK' ), + ( ('CONS', 0x0B7), 'CONSUMER_STOP' ), + ( ('CONS', 0x0B8), 'CONSUMER_EJECT' ), + ( ('CONS', 0x0B9), 'CONSUMER_RANDOM_PLAY' ), + + ( ('CONS', 0x0BC), 'CONSUMER_REPEAT' ), + + ( ('CONS', 0x0BE), 'CONSUMER_TRACK_NORMAL' ), + + ( ('CONS', 0x0C0), 'CONSUMER_FRAME_FORWARD' ), + ( ('CONS', 0x0C1), 'CONSUMER_FRAME_BACK' ), + ( ('CONS', 0x0C2), 'CONSUMER_MARK' ), + ( ('CONS', 0x0C3), 'CONSUMER_CLEAR_MARK' ), + ( ('CONS', 0x0C4), 'CONSUMER_REPEAT_FROM_MARK' ), + ( ('CONS', 0x0C5), 'CONSUMER_RETURN_TO_MARK' ), + ( ('CONS', 0x0C6), 'CONSUMER_SEARCH_MARK_FORWARDS' ), + ( ('CONS', 0x0C7), 'CONSUMER_SEARCH_MARK_BACKWARDS' ), + ( ('CONS', 0x0C8), 'CONSUMER_COUNTER_RESET' ), + ( ('CONS', 0x0C9), 'CONSUMER_SHOW_COUNTER' ), + ( ('CONS', 0x0CA), 'CONSUMER_TRACKING_INCREMENT' ), + ( ('CONS', 0x0CB), 'CONSUMER_TRACKING_DECREMENT' ), + ( ('CONS', 0x0CC), 'CONSUMER_STOP_EJECT' ), + ( ('CONS', 0x0CD), 'CONSUMER_PAUSE_PLAY' ), + ( ('CONS', 0x0CE), 'CONSUMER_PLAY_SKIP' ), +# 0x0CF - 0x0DF Reserved + + ( ('CONS', 0x0E2), 'CONSUMER_MUTE' ), + + ( ('CONS', 0x0E5), 'CONSUMER_BASS_BOOST' ), + ( ('CONS', 0x0E6), 'CONSUMER_SURROUND_MODE' ), + ( ('CONS', 0x0E7), 'CONSUMER_LOUDNESS' ), + ( ('CONS', 0x0E8), 'CONSUMER_MPX' ), + ( ('CONS', 0x0E9), 'CONSUMER_VOLUME_UP' ), + ( ('CONS', 0x0EA), 'CONSUMER_VOLUME_DOWN' ), +# 0x0EB - 0x0EF Reserved + ( ('CONS', 0x0F0), 'CONSUMER_SPEED_SELECT' ), + ( ('CONS', 0x0F2), 'CONSUMER_STANDARD_PLAY' ), + ( ('CONS', 0x0F3), 'CONSUMER_LONG_PLAY' ), + ( ('CONS', 0x0F4), 'CONSUMER_EXTENDED_PLAY' ), + ( ('CONS', 0x0F5), 'CONSUMER_SLOW' ), +# 0x0F6 - 0x0FF + ( ('CONS', 0x100), 'CONSUMER_FAN_ENABLE' ), + + ( ('CONS', 0x102), 'CONSUMER_LIGHT_ENABLE' ), + + ( ('CONS', 0x104), 'CONSUMER_CLIMATE_CONTROL_ENABLE' ), + + ( ('CONS', 0x106), 'CONSUMER_SECURITY_ENABLE' ), + ( ('CONS', 0x107), 'CONSUMER_FIRE_ALARM' ), + + ( ('CONS', 0x10A), 'CONSUMER_MOTION' ), + ( ('CONS', 0x10B), 'CONSUMER_DURESS_ALARM' ), + ( ('CONS', 0x10C), 'CONSUMER_HOLDUP_ALARM' ), + ( ('CONS', 0x10D), 'CONSUMER_MEDICAL_ALARM' ), +# 0x10E - 0x14F Reserved + ( ('CONS', 0x150), 'CONSUMER_BALANCE_RIGHT' ), + ( ('CONS', 0x151), 'CONSUMER_BALANCE_LEFT' ), + ( ('CONS', 0x152), 'CONSUMER_BASS_INCR' ), + ( ('CONS', 0x153), 'CONSUMER_BASS_DECR' ), + ( ('CONS', 0x154), 'CONSUMER_TREBLE_INCR' ), + ( ('CONS', 0x155), 'CONSUMER_TREBLE_DECR' ), +# 0x156 - 0x15F Reserved + + ( ('CONS', 0x171), 'CONSUMER_SUB_CHANNEL_INCREMENT' ), + ( ('CONS', 0x172), 'CONSUMER_SUB_CHANNEL_DECREMENT' ), + ( ('CONS', 0x173), 'CONSUMER_ALT_AUDIO_INCREMENT' ), + ( ('CONS', 0x174), 'CONSUMER_ALT_AUDIO_DECREMENT' ), + +# List of Consumer Codes - USB HID 1.12v2 +# Application Launch Buttons pg 79 + ( ('CONS', 0x181), 'AL_LAUNCH_BUTTON_CONFIG_TOOL' ), + ( ('CONS', 0x182), 'AL_PROGRAMMABLE_BUTTON_CONFIG' ), + ( ('CONS', 0x183), 'AL_CONSUMER_CONTROL_CONFIG' ), + ( ('CONS', 0x184), 'AL_WORD_PROCESSOR' ), + ( ('CONS', 0x185), 'AL_TEXT_EDITOR' ), + ( ('CONS', 0x186), 'AL_SPREADSHEET' ), + ( ('CONS', 0x187), 'AL_GRAPHICS_EDITOR' ), + ( ('CONS', 0x188), 'AL_PRESENTATION_APP' ), + ( ('CONS', 0x189), 'AL_DATABASE_APP' ), + ( ('CONS', 0x18A), 'AL_EMAIL_READER' ), + ( ('CONS', 0x18B), 'AL_NEWSREADER' ), + ( ('CONS', 0x18C), 'AL_VOICEMAIL' ), + ( ('CONS', 0x18D), 'AL_CONTACTS_ADDRESS_BOOK' ), + ( ('CONS', 0x18E), 'AL_CALENDAR_SCHEDULE' ), + ( ('CONS', 0x18F), 'AL_TASK_PROJECT_MANAGER' ), + ( ('CONS', 0x190), 'AL_LOG_JOURNAL_TIMECARD' ), + ( ('CONS', 0x191), 'AL_CHECKBOOK_FINANCE' ), + ( ('CONS', 0x192), 'AL_CALCULATOR' ), + ( ('CONS', 0x193), 'AL_A_V_CAPTURE_PLAYBACK' ), + ( ('CONS', 0x194), 'AL_LOCAL_MACHINE_BROWSER' ), + ( ('CONS', 0x195), 'AL_LAN_WAN_BROWSER' ), + ( ('CONS', 0x196), 'AL_INTERNET_BROWSER' ), + ( ('CONS', 0x197), 'AL_REMOTE_NETWORKING_ISP_CONNECT' ), + ( ('CONS', 0x198), 'AL_NETWORK_CONFERENCE' ), + ( ('CONS', 0x199), 'AL_NETWORK_CHAT' ), + ( ('CONS', 0x19A), 'AL_TELEPHONY_DIALER' ), + ( ('CONS', 0x19B), 'AL_LOGON' ), + ( ('CONS', 0x19C), 'AL_LOGOFF' ), + ( ('CONS', 0x19D), 'AL_LOGON_LOGOFF' ), + ( ('CONS', 0x19E), 'AL_TERMINAL_LOCK_SCREENSAVER' ), + ( ('CONS', 0x19F), 'AL_CONTROL_PANEL' ), + ( ('CONS', 0x1A0), 'AL_COMMAND_LINE_PROCESSOR_RUN' ), + ( ('CONS', 0x1A1), 'AL_PROCESS_TASK_MANAGER' ), + ( ('CONS', 0x1A2), 'AL_SELECT_TAST_APP' ), + ( ('CONS', 0x1A3), 'AL_NEXT_TASK_APP' ), + ( ('CONS', 0x1A4), 'AL_PREVIOUS_TASK_APP' ), + ( ('CONS', 0x1A5), 'AL_PREEMPTIVE_HALT_TASK_APP' ), + ( ('CONS', 0x1A6), 'AL_INTEGRATED_HELP_CENTER' ), + ( ('CONS', 0x1A7), 'AL_DOCUMENTS' ), + ( ('CONS', 0x1A8), 'AL_THESAURUS' ), + ( ('CONS', 0x1A9), 'AL_DICTIONARY' ), + ( ('CONS', 0x1AA), 'AL_DESKTOP' ), + ( ('CONS', 0x1AB), 'AL_SPELL_CHECK' ), + ( ('CONS', 0x1AC), 'AL_GRAMMAR_CHECK' ), + ( ('CONS', 0x1AD), 'AL_WIRELESS_STATUS' ), + ( ('CONS', 0x1AE), 'AL_KEYBOARD_LAYOUT' ), + ( ('CONS', 0x1AF), 'AL_VIRUS_PROTECTION' ), + ( ('CONS', 0x1B0), 'AL_ENCRYPTION' ), + ( ('CONS', 0x1B1), 'AL_SCREEN_SAVER' ), + ( ('CONS', 0x1B2), 'AL_ALARMS' ), + ( ('CONS', 0x1B3), 'AL_CLOCK' ), + ( ('CONS', 0x1B4), 'AL_FILE_BROWSER' ), + ( ('CONS', 0x1B5), 'AL_POWER_STATUS' ), + ( ('CONS', 0x1B6), 'AL_IMAGE_BROWSER' ), + ( ('CONS', 0x1B7), 'AL_AUDIO_BROWSER' ), + ( ('CONS', 0x1B8), 'AL_MOVIE_BROWSER' ), + ( ('CONS', 0x1B9), 'AL_DIGITAL_RIGHTS_MANAGER' ), + ( ('CONS', 0x1BA), 'AL_DIGITAL_WALLET' ), +# 0x1BB Reserved + ( ('CONS', 0x1BC), 'AL_INSTANT_MESSAGING' ), + ( ('CONS', 0x1BD), 'AL_OEM_FEATURES_TIPS_TUTORIAL' ), + ( ('CONS', 0x1BE), 'AL_OEM_HELP' ), + ( ('CONS', 0x1BF), 'AL_ONLINE_COMMUNITY' ), + ( ('CONS', 0x1C0), 'AL_ENTERTAINMENT_CONTENT' ), + ( ('CONS', 0x1C1), 'AL_ONLINE_SHOPPING' ), + ( ('CONS', 0x1C2), 'AL_SMARTCARD_INFO_HELP' ), + ( ('CONS', 0x1C3), 'AL_MARKET_MONITOR' ), + ( ('CONS', 0x1C4), 'AL_CUSTOMIZED_CORP_NEWS' ), + ( ('CONS', 0x1C5), 'AL_ONLINE_ACTIVITY' ), + ( ('CONS', 0x1C6), 'AL_SEARCH_BROWSER' ), + ( ('CONS', 0x1C7), 'AL_AUDIO_PLAYER' ), + +# List of Consumer Codes - USB HID 1.12v2 +# Generic GUI Application Controls pg 82 + ( ('CONS', 0x201), 'AC_NEW' ), + ( ('CONS', 0x202), 'AC_OPEN' ), + ( ('CONS', 0x203), 'AC_CLOSE' ), + ( ('CONS', 0x204), 'AC_EXIT' ), + ( ('CONS', 0x205), 'AC_MAXIMIZE' ), + ( ('CONS', 0x206), 'AC_MINIMIZE' ), + ( ('CONS', 0x207), 'AC_SAVE' ), + ( ('CONS', 0x208), 'AC_PRINT' ), + ( ('CONS', 0x209), 'AC_PROPERTIES' ), + ( ('CONS', 0x21A), 'AC_UNDO' ), + ( ('CONS', 0x21B), 'AC_COPY' ), + ( ('CONS', 0x21C), 'AC_CUT' ), + ( ('CONS', 0x21D), 'AC_PASTE' ), + ( ('CONS', 0x21E), 'AC_SELECT_ALL' ), + ( ('CONS', 0x21F), 'AC_FIND' ), + ( ('CONS', 0x220), 'AC_FIND_AND_REPLACE' ), + ( ('CONS', 0x221), 'AC_SEARCH' ), + ( ('CONS', 0x222), 'AC_GO_TO' ), + ( ('CONS', 0x223), 'AC_HOME' ), + ( ('CONS', 0x224), 'AC_BACK' ), + ( ('CONS', 0x225), 'AC_FORWARD' ), + ( ('CONS', 0x226), 'AC_STOP' ), + ( ('CONS', 0x227), 'AC_REFRESH' ), + ( ('CONS', 0x228), 'AC_PREVIOUS_LINK' ), + ( ('CONS', 0x229), 'AC_NEXT_LINK' ), + ( ('CONS', 0x22A), 'AC_BOOKMARKS' ), + ( ('CONS', 0x22B), 'AC_HISTORY' ), + ( ('CONS', 0x22C), 'AC_SUBSCRIPTIONS' ), + ( ('CONS', 0x22D), 'AC_ZOOM_IN' ), + ( ('CONS', 0x22E), 'AC_ZOOM_OUT' ), + ( ('CONS', 0x22F), 'AC_ZOOM' ), + ( ('CONS', 0x230), 'AC_FULL_SCREEN_VIEW' ), + ( ('CONS', 0x231), 'AC_NORMAL_VIEW' ), + ( ('CONS', 0x232), 'AC_VIEW_TOGGLE' ), + ( ('CONS', 0x233), 'AC_SCROLL_UP' ), + ( ('CONS', 0x234), 'AC_SCROLL_DOWN' ), + ( ('CONS', 0x235), 'AC_SCROLL' ), + ( ('CONS', 0x236), 'AC_PAN_LEFT' ), + ( ('CONS', 0x237), 'AC_PAN_RIGHT' ), + ( ('CONS', 0x238), 'AC_PAN' ), + ( ('CONS', 0x239), 'AC_NEW_WINDOW' ), + ( ('CONS', 0x23A), 'AC_TILE_HORIZONTALLY' ), + ( ('CONS', 0x23B), 'AC_TILE_VERTICALLY' ), + ( ('CONS', 0x23C), 'AC_FORMAT' ), + ( ('CONS', 0x23D), 'AC_EDIT' ), + ( ('CONS', 0x23E), 'AC_BOLD' ), + ( ('CONS', 0x23F), 'AC_ITALICS' ), + ( ('CONS', 0x240), 'AC_UNDERLINE' ), + ( ('CONS', 0x241), 'AC_STRIKETHROUGH' ), + ( ('CONS', 0x242), 'AC_SUBSCRIPT' ), + ( ('CONS', 0x243), 'AC_SUPERSCRIPT' ), + ( ('CONS', 0x244), 'AC_ALL_CAPS' ), + ( ('CONS', 0x245), 'AC_ROTATE' ), + ( ('CONS', 0x246), 'AC_RESIZE' ), + ( ('CONS', 0x247), 'AC_FILP_HORIZONTAL' ), + ( ('CONS', 0x248), 'AC_FILP_VERTICAL' ), + ( ('CONS', 0x249), 'AC_MIRROR_HORIZONTAL' ), + ( ('CONS', 0x24A), 'AC_MIRROR_VERTICAL' ), + ( ('CONS', 0x24B), 'AC_FONT_SELECT' ), + ( ('CONS', 0x24C), 'AC_FONT_COLOR' ), + ( ('CONS', 0x24D), 'AC_FONT_SIZE' ), + ( ('CONS', 0x24E), 'AC_JUSTIFY_LEFT' ), + ( ('CONS', 0x24F), 'AC_JUSTIFY_CENTER_H' ), + ( ('CONS', 0x250), 'AC_JUSTIFY_RIGHT' ), + ( ('CONS', 0x251), 'AC_JUSTIFY_BLOCK_H' ), + ( ('CONS', 0x252), 'AC_JUSTIFY_TOP' ), + ( ('CONS', 0x253), 'AC_JUSTIFY_CENTER_V' ), + ( ('CONS', 0x254), 'AC_JUSTIFY_BOTTOM' ), + ( ('CONS', 0x255), 'AC_JUSTIFY_BLOCK_V' ), + ( ('CONS', 0x256), 'AC_INDENT_DECREASE' ), + ( ('CONS', 0x257), 'AC_INDENT_INCREASE' ), + ( ('CONS', 0x258), 'AC_NUMBERED_LIST' ), + ( ('CONS', 0x259), 'AC_RESTART_NUMBERING' ), + ( ('CONS', 0x25A), 'AC_BULLETED_LIST' ), + ( ('CONS', 0x25B), 'AC_PROMOTE' ), + ( ('CONS', 0x25C), 'AC_DEMOTE' ), + ( ('CONS', 0x25D), 'AC_YES' ), + ( ('CONS', 0x25E), 'AC_NO' ), + ( ('CONS', 0x25F), 'AC_CANCEL' ), + ( ('CONS', 0x260), 'AC_CATALOG' ), + ( ('CONS', 0x261), 'AC_BUY_CHECKOUT' ), + ( ('CONS', 0x262), 'AC_ADD_TO_CART' ), + ( ('CONS', 0x263), 'AC_EXPAND' ), + ( ('CONS', 0x264), 'AC_EXPAND_ALL' ), + ( ('CONS', 0x265), 'AC_COLLAPSE' ), + ( ('CONS', 0x266), 'AC_COLLAPSE_ALL' ), + ( ('CONS', 0x267), 'AC_PRINT_PREVIEW' ), + ( ('CONS', 0x268), 'AC_PASTE_SPECIAL' ), + ( ('CONS', 0x269), 'AC_INSERT_MODE' ), + ( ('CONS', 0x26A), 'AC_DELETE' ), + ( ('CONS', 0x26B), 'AC_LOCK' ), + ( ('CONS', 0x26C), 'AC_UNLOCK' ), + ( ('CONS', 0x26D), 'AC_PROTECT' ), + ( ('CONS', 0x26E), 'AC_UNPROTECT' ), + ( ('CONS', 0x26F), 'AC_ATTACH_COMMENT' ), + ( ('CONS', 0x270), 'AC_DELETE_COMMENT' ), + ( ('CONS', 0x271), 'AC_VIEW_COMMENT' ), + ( ('CONS', 0x272), 'AC_SELECT_WORD' ), + ( ('CONS', 0x273), 'AC_SELECT_SENTENCE' ), + ( ('CONS', 0x274), 'AC_SELECT_PARAGRAPH' ), + ( ('CONS', 0x275), 'AC_SELECT_COLUMN' ), + ( ('CONS', 0x276), 'AC_SELECT_ROW' ), + ( ('CONS', 0x277), 'AC_SELECT_TABLE' ), + ( ('CONS', 0x278), 'AC_SELECT_OBJECT' ), + ( ('CONS', 0x279), 'AC_REDO_REPEAT' ), + ( ('CONS', 0x27A), 'AC_SORT' ), + ( ('CONS', 0x27B), 'AC_SORT_ASCENDING' ), + ( ('CONS', 0x27C), 'AC_SORT_DESCENDING' ), + ( ('CONS', 0x27D), 'AC_FILTER' ), + ( ('CONS', 0x27E), 'AC_SET_CLOCK' ), + ( ('CONS', 0x27F), 'AC_VIEW_CLOCK' ), + ( ('CONS', 0x280), 'AC_SELECT_TIME_ZONE' ), + ( ('CONS', 0x281), 'AC_EDIT_TIME_ZONE' ), + ( ('CONS', 0x282), 'AC_SET_ALARM' ), + ( ('CONS', 0x283), 'AC_CLEAR_ALARM' ), + ( ('CONS', 0x284), 'AC_SNOOZE_ALARM' ), + ( ('CONS', 0x285), 'AC_RESET_ALARM' ), + ( ('CONS', 0x286), 'AC_SYNCHRONIZE' ), + ( ('CONS', 0x287), 'AC_SEND_RECEIVE' ), + ( ('CONS', 0x288), 'AC_SEND_TO' ), + ( ('CONS', 0x289), 'AC_REPLY' ), + ( ('CONS', 0x28A), 'AC_REPLY_ALL' ), + ( ('CONS', 0x28B), 'AC_FORWARD_MSG' ), + ( ('CONS', 0x28C), 'AC_SEND' ), + ( ('CONS', 0x28D), 'AC_ATTACH_FILE' ), + ( ('CONS', 0x28E), 'AC_UPLOAD' ), + ( ('CONS', 0x28F), 'AC_DOWNLOAD' ), + ( ('CONS', 0x290), 'AC_SET_BORDERS' ), + ( ('CONS', 0x291), 'AC_INSERT_ROW' ), + ( ('CONS', 0x292), 'AC_INSERT_COLUMN' ), + ( ('CONS', 0x293), 'AC_INSERT_FILE' ), + ( ('CONS', 0x294), 'AC_INSERT_PICTURE' ), + ( ('CONS', 0x295), 'AC_INSERT_OBJECT' ), + ( ('CONS', 0x296), 'AC_INSERT_SYMBOL' ), + ( ('CONS', 0x297), 'AC_SAVE_AND_CLOSE' ), + ( ('CONS', 0x298), 'AC_RENAME' ), + ( ('CONS', 0x299), 'AC_MERGE' ), + ( ('CONS', 0x29A), 'AC_SPLIT' ), + ( ('CONS', 0x29B), 'AC_DISTRIBUTE_HORIZONTALLY' ), + ( ('CONS', 0x29C), 'AC_DISTRIBUTE_VERTICALLY' ), + ( ('CONS', 0x29D), 'AC_NEXT_KEYBOARD_LAYOUT_SEL' ), +# 0x29E-0xFFFF Reserved + + # USB HID LED Codes + ( ('IND', 0x00), 'LED_UNDEFINED' ), + ( ('IND', 0x01), 'LED_NUM_LOCK' ), + ( ('IND', 0x02), 'LED_CAPS_LOCK' ), + ( ('IND', 0x03), 'LED_SCROLL_LOCK' ), + ( ('IND', 0x04), 'LED_COMPOSE' ), + ( ('IND', 0x05), 'LED_KANA' ), + ( ('IND', 0x06), 'LED_POWER' ), + ( ('IND', 0x07), 'LED_SHIFT' ), + ( ('IND', 0x08), 'LED_DO_NOT_DISTURB' ), + ( ('IND', 0x09), 'LED_MUTE' ), + ( ('IND', 0x0A), 'LED_TONE_ENABLE' ), + ( ('IND', 0x0B), 'LED_HIGHCUT_FILTER' ), + ( ('IND', 0x0C), 'LED_LOWCUT_FILTER' ), + ( ('IND', 0x0D), 'LED_EQL_ENABLE' ), + ( ('IND', 0x0E), 'LED_SND_FLD_ON' ), + ( ('IND', 0x0F), 'LED_SURROUND_ON' ), + ( ('IND', 0x10), 'LED_REPEAT' ), + ( ('IND', 0x11), 'LED_STEREO' ), + ( ('IND', 0x12), 'LED_SAMPLE_RT_DET' ), + ( ('IND', 0x13), 'LED_SPINNING' ), + ( ('IND', 0x14), 'LED_CAV' ), + ( ('IND', 0x15), 'LED_CLV' ), + ( ('IND', 0x16), 'LED_REC_FMT_DET' ), + ( ('IND', 0x17), 'LED_OFF_HOOK' ), + ( ('IND', 0x18), 'LED_RING' ), + ( ('IND', 0x19), 'LED_MSG_WAITING' ), + ( ('IND', 0x1A), 'LED_DATA_MODE' ), + ( ('IND', 0x1B), 'LED_BAT_OPERATION' ), + ( ('IND', 0x1C), 'LED_BAT_OK' ), + ( ('IND', 0x1D), 'LED_BAT_LOW' ), + ( ('IND', 0x1E), 'LED_SPEAKER' ), + ( ('IND', 0x1F), 'LED_HEAD_SET' ), + ( ('IND', 0x20), 'LED_HOLD' ), + ( ('IND', 0x21), 'LED_MICROPHONE' ), + ( ('IND', 0x22), 'LED_COVERAGE' ), + ( ('IND', 0x23), 'LED_NIGHT_MODE' ), + ( ('IND', 0x24), 'LED_SEND_CALLS' ), + ( ('IND', 0x25), 'LED_CALL_PICKUP' ), + ( ('IND', 0x26), 'LED_CONFERENCE' ), + ( ('IND', 0x27), 'LED_STAND_BY' ), + ( ('IND', 0x28), 'LED_CAMERA_ON' ), + ( ('IND', 0x29), 'LED_CAMERA_OFF' ), + ( ('IND', 0x2A), 'LED_ON_LINE' ), + ( ('IND', 0x2B), 'LED_OFF_LINE' ), + ( ('IND', 0x2C), 'LED_BUSY' ), + ( ('IND', 0x2D), 'LED_READY' ), + ( ('IND', 0x2E), 'LED_PAPER_OUT' ), + ( ('IND', 0x2F), 'LED_PAPER_JAM' ), + ( ('IND', 0x30), 'LED_REMOTE' ), + ( ('IND', 0x31), 'LED_FORWARD' ), + ( ('IND', 0x32), 'LED_REVERSE' ), + ( ('IND', 0x33), 'LED_STOP' ), + ( ('IND', 0x34), 'LED_REWIND' ), + ( ('IND', 0x35), 'LED_FAST_FORWARD' ), + ( ('IND', 0x36), 'LED_PLAY' ), + ( ('IND', 0x37), 'LED_PAUSE' ), + ( ('IND', 0x38), 'LED_RECORD' ), + ( ('IND', 0x39), 'LED_ERROR' ), + ( ('IND', 0x3A), 'LED_USI' ), + ( ('IND', 0x3B), 'LED_UIUI' ), + ( ('IND', 0x3C), 'LED_UMMI' ), + ( ('IND', 0x3D), 'LED_IND_ON' ), + ( ('IND', 0x3E), 'LED_IND_FLASH' ), + ( ('IND', 0x3F), 'LED_IND_SLOW_BLNK' ), + ( ('IND', 0x40), 'LED_IND_FAST_BLNK' ), + ( ('IND', 0x41), 'LED_IND_OFF' ), + ( ('IND', 0x42), 'LED_FLASH_ON_TIME' ), + ( ('IND', 0x43), 'LED_SLW_B_ON_TIME' ), + ( ('IND', 0x44), 'LED_SLW_B_OFF_TIME' ), + ( ('IND', 0x45), 'LED_FST_B_ON_TIME' ), + ( ('IND', 0x46), 'LED_FST_B_OFF_TIME' ), + ( ('IND', 0x47), 'LED_UIC' ), + ( ('IND', 0x48), 'LED_IND_RED' ), + ( ('IND', 0x49), 'LED_IND_GREEN' ), + ( ('IND', 0x4A), 'LED_IND_AMBER' ), + ( ('IND', 0x4B), 'LED_GENERIC_IND' ), + ( ('IND', 0x4C), 'LED_SYS_SUSPEND' ), + ( ('IND', 0x4D), 'LED_EXT_PWR_CONN' ), +# 0x4E - 0xFFFF Reserved + + # USB HID System Control Codes +# List of System Controls - USB HID 1.12v2 pg 32 +# NKRO HID Supports 0x81 - 0xB7 + ( ('SYS', 0x81), 'SYS_POWER_DOWN' ), + ( ('SYS', 0x82), 'SYS_SLEEP' ), + ( ('SYS', 0x83), 'SYS_WAKE_UP' ), + ( ('SYS', 0x84), 'SYS_CONTEXT_MENU' ), + ( ('SYS', 0x85), 'SYS_MAIN_MENU' ), + ( ('SYS', 0x86), 'SYS_APP_MENU' ), + ( ('SYS', 0x87), 'SYS_MENU_HELP' ), + ( ('SYS', 0x88), 'SYS_MENU_EXIT' ), + ( ('SYS', 0x89), 'SYS_MENU_SELECT' ), + ( ('SYS', 0x8A), 'SYS_MENU_RIGHT' ), + ( ('SYS', 0x8B), 'SYS_MENU_LEFT' ), + ( ('SYS', 0x8C), 'SYS_MENU_UP' ), + ( ('SYS', 0x8D), 'SYS_MENU_DOWN' ), + ( ('SYS', 0x8E), 'SYS_COLD_RESTART' ), + ( ('SYS', 0x8F), 'SYS_WARM_RESTART' ), + ( ('SYS', 0x90), 'SYS_DPAD_UP' ), + ( ('SYS', 0x91), 'SYS_DPAD_DOWN' ), + ( ('SYS', 0x92), 'SYS_DPAD_RIGHT' ), + ( ('SYS', 0x93), 'SYS_DPAD_LEFT' ), +# 0x94 - 0x9F Reserved + ( ('SYS', 0xA0), 'SYS_DOCK' ), + ( ('SYS', 0xA1), 'SYS_UNDOCK' ), + ( ('SYS', 0xA2), 'SYS_SETUP' ), + ( ('SYS', 0xA3), 'SYS_BREAK' ), + ( ('SYS', 0xA4), 'SYS_DEBUGGER_BREAK' ), + ( ('SYS', 0xA5), 'SYS_APP_BREAK' ), + ( ('SYS', 0xA6), 'SYS_APP_DEBUGGER_BREAK' ), + ( ('SYS', 0xA7), 'SYS_SPEAKER_MUTE' ), + ( ('SYS', 0xA8), 'SYS_HIBERNATE' ), +# 0xA9 - 0xAF Reserved + ( ('SYS', 0xB0), 'SYS_DISP_INVERT' ), + ( ('SYS', 0xB1), 'SYS_DISP_INTERNAL' ), + ( ('SYS', 0xB2), 'SYS_DISP_EXTERNAL' ), + ( ('SYS', 0xB3), 'SYS_DISP_BOTH' ), + ( ('SYS', 0xB4), 'SYS_DISP_DUAL' ), + ( ('SYS', 0xB5), 'SYS_DISP_TOGGLE_INT_EXT' ), + ( ('SYS', 0xB6), 'SYS_DISP_SWAP_PRI_SEC' ), + ( ('SYS', 0xB7), 'SYS_DISP_LCD_AUTOSCALE' ), +# 0xB8 - 0xFFFF Reserved +]) + + + +# Lookup for KLL defined HID values, internally the compiler uses numbers to combine the keymaps +kll_hid_lookup_dictionary = dict() +kll_hid_lookup_dictionary['USBCode'] = dict([ + # USB HID Keyboard Codes + ( 'A', ('USB', 0x04) ), + ( 'B', ('USB', 0x05) ), + ( 'C', ('USB', 0x06) ), + ( 'D', ('USB', 0x07) ), + ( 'E', ('USB', 0x08) ), + ( 'F', ('USB', 0x09) ), + ( 'G', ('USB', 0x0A) ), + ( 'H', ('USB', 0x0B) ), + ( 'I', ('USB', 0x0C) ), + ( 'J', ('USB', 0x0D) ), + ( 'K', ('USB', 0x0E) ), + ( 'L', ('USB', 0x0F) ), + ( 'M', ('USB', 0x10) ), + ( 'N', ('USB', 0x11) ), + ( 'O', ('USB', 0x12) ), + ( 'P', ('USB', 0x13) ), + ( 'Q', ('USB', 0x14) ), + ( 'R', ('USB', 0x15) ), + ( 'S', ('USB', 0x16) ), + ( 'T', ('USB', 0x17) ), + ( 'U', ('USB', 0x18) ), + ( 'V', ('USB', 0x19) ), + ( 'W', ('USB', 0x1A) ), + ( 'X', ('USB', 0x1B) ), + ( 'Y', ('USB', 0x1C) ), + ( 'Z', ('USB', 0x1D) ), + ( '1', ('USB', 0x1E) ), + ( '2', ('USB', 0x1F) ), + ( '3', ('USB', 0x20) ), + ( '4', ('USB', 0x21) ), + ( '5', ('USB', 0x22) ), + ( '6', ('USB', 0x23) ), + ( '7', ('USB', 0x24) ), + ( '8', ('USB', 0x25) ), + ( '9', ('USB', 0x26) ), + ( '0', ('USB', 0x27) ), + ( 'ENTER', ('USB', 0x28) ), + ( 'ESC', ('USB', 0x29) ), ( 'ESCAPE', ('USB', 0x29) ), + ( 'BACKSPACE', ('USB', 0x2A) ), + ( 'TAB', ('USB', 0x2B) ), + ( 'SPACE', ('USB', 0x2C) ), ( 'SPACEBAR', ('USB', 0x2C) ), + ( '-', ('USB', 0x2D) ), ( 'MINUS', ('USB', 0x2D) ), + ( '=', ('USB', 0x2E) ), ( 'EQUALS', ('USB', 0x2E) ), ( 'EQUAL', ('USB', 0x2E) ), + ( '[', ('USB', 0x2F) ), ( 'LEFT BRACKET', ('USB', 0x2F) ), ( 'LBRACKET', ('USB', 0x2F) ), ( 'LEFT BRACE', ('USB', 0x2F) ), ( 'LBRACE', ('USB', 0x2F) ), + ( ']', ('USB', 0x30) ), ( 'RIGHT BRACKET', ('USB', 0x30) ), ( 'RBRACKET', ('USB', 0x30) ), ( 'RIGHT BRACE', ('USB', 0x30) ), ( 'RBRACE', ('USB', 0x30) ), + ( '\\', ('USB', 0x31) ), ( 'BACKSLASH', ('USB', 0x31) ), + ( '#', ('USB', 0x32) ), ( 'NUMBER', ('USB', 0x32) ), ( 'HASH', ('USB', 0x32) ), + ( ';', ('USB', 0x33) ), ( 'SEMICOLON', ('USB', 0x33) ), + ( "'", ('USB', 0x34) ), ( 'QUOTE', ('USB', 0x34) ), ( 'SINGLE QUOTE', ('USB', 0x34) ), + ( '`', ('USB', 0x35) ), ( 'BACKTICK', ('USB', 0x35) ), + ( ',', ('USB', 0x36) ), ( 'COMMA', ('USB', 0x36) ), + ( '.', ('USB', 0x37) ), ( 'PERIOD', ('USB', 0x37) ), + ( '/', ('USB', 0x38) ), ( 'SLASH', ('USB', 0x38) ), + ( 'CAPSLOCK', ('USB', 0x39) ), { 'CAPS LOCK', ('USB', 0x39) }, + ( 'F1', ('USB', 0x3A) ), + ( 'F2', ('USB', 0x3B) ), + ( 'F3', ('USB', 0x3C) ), + ( 'F4', ('USB', 0x3D) ), + ( 'F5', ('USB', 0x3E) ), + ( 'F6', ('USB', 0x3F) ), + ( 'F7', ('USB', 0x40) ), + ( 'F8', ('USB', 0x41) ), + ( 'F9', ('USB', 0x42) ), + ( 'F10', ('USB', 0x43) ), + ( 'F11', ('USB', 0x44) ), + ( 'F12', ('USB', 0x45) ), + ( 'PRINTSCREEN', ('USB', 0x46) ), ( 'PRINT SCREEN', ('USB', 0x46) ), + ( 'SCROLLLOCK', ('USB', 0x47) ), ( 'SCROLL LOCK', ('USB', 0x47) ), + ( 'PAUSE', ('USB', 0x48) ), + ( 'INSERT', ('USB', 0x49) ), + ( 'HOME', ('USB', 0x4A) ), + ( 'PAGEUP', ('USB', 0x4B) ), ( 'PAGE UP', ('USB', 0x4B) ), + ( 'DELETE', ('USB', 0x4C) ), + ( 'END', ('USB', 0x4D) ), + ( 'PAGEDOWN', ('USB', 0x4E) ), ( 'PAGE DOWN', ('USB', 0x4E) ), + ( 'RIGHT', ('USB', 0x4F) ), + ( 'LEFT', ('USB', 0x50) ), + ( 'DOWN', ('USB', 0x51) ), + ( 'UP', ('USB', 0x52) ), + ( 'NUMLOCK', ('USB', 0x53) ), ( 'NUM LOCK', ('USB', 0x53) ), + ( 'P/', ('USB', 0x54) ), ( 'KEYPAD SLASH', ('USB', 0x54) ), + ( 'P*', ('USB', 0x55) ), ( 'KEYPAD ASTERIX', ('USB', 0x55) ), ( 'KEYPAD ASTERISK', ('USB', 0x55) ), + ( 'P-', ('USB', 0x56) ), ( 'KEYPAD MINUS', ('USB', 0x56) ), + ( 'P+', ('USB', 0x57) ), ( 'KEYPAD PLUS', ('USB', 0x57) ), + ( 'PENTER', ('USB', 0x58) ), ( 'KEYPAD ENTER', ('USB', 0x58) ), + ( 'P1', ('USB', 0x59) ), ( 'KEYPAD 1', ('USB', 0x59) ), + ( 'P2', ('USB', 0x5A) ), ( 'KEYPAD 2', ('USB', 0x5A) ), + ( 'P3', ('USB', 0x5B) ), ( 'KEYPAD 3', ('USB', 0x5B) ), + ( 'P4', ('USB', 0x5C) ), ( 'KEYPAD 4', ('USB', 0x5C) ), + ( 'P5', ('USB', 0x5D) ), ( 'KEYPAD 5', ('USB', 0x5D) ), + ( 'P6', ('USB', 0x5E) ), ( 'KEYPAD 6', ('USB', 0x5E) ), + ( 'P7', ('USB', 0x5F) ), ( 'KEYPAD 7', ('USB', 0x5F) ), + ( 'P8', ('USB', 0x60) ), ( 'KEYPAD 8', ('USB', 0x60) ), + ( 'P9', ('USB', 0x61) ), ( 'KEYPAD 9', ('USB', 0x61) ), + ( 'P0', ('USB', 0x62) ), ( 'KEYPAD 0', ('USB', 0x62) ), + ( 'P.', ('USB', 0x63) ), ( 'KEYPAD PERIOD', ('USB', 0x63) ), + ( 'ISO/', ('USB', 0x64) ), ( 'ISO SLASH', ('USB', 0x64) ), + ( 'APP', ('USB', 0x65) ), + + ( 'P=', ('USB', 0x67) ), ( 'KEYPAD EQUAL', ('USB', 0x67) ), + ( 'F13', ('USB', 0x68) ), + ( 'F14', ('USB', 0x69) ), + ( 'F15', ('USB', 0x6A) ), + ( 'F16', ('USB', 0x6B) ), + ( 'F17', ('USB', 0x6C) ), + ( 'F18', ('USB', 0x6D) ), + ( 'F19', ('USB', 0x6E) ), + ( 'F20', ('USB', 0x6F) ), + ( 'F21', ('USB', 0x70) ), + ( 'F22', ('USB', 0x71) ), + ( 'F23', ('USB', 0x72) ), + ( 'F24', ('USB', 0x73) ), + ( 'EXEC', ('USB', 0x74) ), + ( 'HELP', ('USB', 0x75) ), + ( 'MENU', ('USB', 0x76) ), + ( 'SELECT', ('USB', 0x77) ), + ( 'STOP', ('USB', 0x78) ), + ( 'AGAIN', ('USB', 0x79) ), + ( 'UNDO', ('USB', 0x7A) ), + ( 'CUT', ('USB', 0x7B) ), + ( 'COPY', ('USB', 0x7C) ), + ( 'PASTE', ('USB', 0x7D) ), + ( 'FIND', ('USB', 0x7E) ), + ( 'MUTE', ('USB', 0x7F) ), + ( 'VOLUMEUP', ('USB', 0x80) ), ( 'VOLUME UP', ('USB', 0x80) ), + ( 'VOLUMEDOWN', ('USB', 0x81) ), ( 'VOLUME DOWN', ('USB', 0x81) ), + ( 'CAPSTOGGLELOCK', ('USB', 0x82) ), ( 'CAPS TOGGLE LOCK', ('USB', 0x82) ), + ( 'NUMTOGGLELOCK', ('USB', 0x83) ), ( 'NUM TOGGLE LOCK', ('USB', 0x83) ), + ( 'SCROLLTOGGLELOCK', ('USB', 0x84) ), ( 'SCROLL TOGGLE LOCK', ('USB', 0x84) ), + ( 'P,', ('USB', 0x85) ), + ( 'KEYPAD AS400 EQUAL', ('USB', 0x86) ), + ( 'INTER1', ('USB', 0x87) ), ( 'KANJI1', ('USB', 0x87) ), + ( 'INTER2', ('USB', 0x88) ), ( 'KANJI2', ('USB', 0x88) ), ( 'KANA', ('USB', 0x88) ), ( 'カナ', ('USB', 0x88) ), + ( 'INTER3', ('USB', 0x89) ), ( 'KANJI3', ('USB', 0x89) ), ( 'YEN', ('USB', 0x89) ), ( '¥', ('USB', 0x89) ), + ( 'INTER4', ('USB', 0x8A) ), ( 'KANJI4', ('USB', 0x8A) ), ( 'HENKAN', ('USB', 0x8A) ), ( '変換', ('USB', 0x8A) ), + ( 'INTER5', ('USB', 0x8B) ), ( 'KANJI5', ('USB', 0x8B) ), ( 'MUHENKAN', ('USB', 0x8B) ), ( '無変換', ('USB', 0x8B) ), + ( 'INTER6', ('USB', 0x8C) ), ( 'KANJI6', ('USB', 0x8C) ), + ( 'INTER7', ('USB', 0x8D) ), ( 'KANJI7', ('USB', 0x8D) ), ( 'BYTETOGGLE', ('USB', 0x8D) ), + ( 'INTER8', ('USB', 0x8E) ), ( 'KANJI8', ('USB', 0x8E) ), + ( 'INTER9', ('USB', 0x8F) ), ( 'KANJI9', ('USB', 0x8F) ), + ( 'LANG1', ('USB', 0x90) ), ( 'HANGULENGLISH', ('USB', 0x90) ), ( 'HANGUL ENGLISH', ('USB', 0x90) ), ( '한/영', ('USB', 0x90) ), + ( 'LANG2', ('USB', 0x91) ), ( 'HANJA', ('USB', 0x91) ), ( 'EISU', ('USB', 0x91) ), ( '英数/한자', ('USB', 0x91) ), + ( 'LANG3', ('USB', 0x92) ), ( 'KATAKANA', ('USB', 0x92) ), ( 'カタカナ', ('USB', 0x92) ), + ( 'LANG4', ('USB', 0x93) ), ( 'HIRAGANA', ('USB', 0x93) ), ( 'ひらがな', ('USB', 0x92) ), + ( 'LANG5', ('USB', 0x94) ), ( 'ZENKAKUHANKAKU', ('USB', 0x94) ), ( 'ZENKAKU HANKAKU', ('USB', 0x94) ), ( '半角/全角', ('USB', 0x94) ), + ( 'LANG6', ('USB', 0x95) ), + ( 'LANG7', ('USB', 0x96) ), + ( 'LANG8', ('USB', 0x97) ), + ( 'LANG9', ('USB', 0x98) ), + ( 'ALTERASE', ('USB', 0x99) ), ( 'ALT ERASE', ('USB', 0x99) ), + ( 'SYSREQATT', ('USB', 0x9A) ), ( 'SYSREQ', ('USB', 0x9A) ), ( 'SYSTEM REQUEST', ('USB', 0x9A) ), + ( 'CANCEL', ('USB', 0x9B) ), + ( 'CLEAR', ('USB', 0x9C) ), + ( 'PRIOR', ('USB', 0x9D) ), + ( 'RETURN', ('USB', 0x9E) ), + ( 'SEP', ('USB', 0x9F) ), ( 'SEPARATOR', ('USB', 0x9F) ), + ( 'OUT', ('USB', 0xA0) ), + ( 'OPER', ('USB', 0xA1) ), + ( 'CLEAR AGAIN', ('USB', 0xA2) ), + ( 'CRSEL PROPS', ('USB', 0xA3) ), + ( 'EXSEL', ('USB', 0xA4) ), + + ( 'P00', ('USB', 0xB0) ), ( 'KEYPAD 00', ('USB', 0xB0) ), + ( 'P000', ('USB', 0xB1) ), ( 'KEYPAD 000', ('USB', 0xB1) ), + ( '1000SEP', ('USB', 0xB2) ), ( 'THOUSANDSEPARATOR', ('USB', 0xB2) ), ( 'THOUSAND SEPARATOR', ('USB', 0xB2) ), + ( 'DECIMALSEP', ('USB', 0xB3) ), ( 'DECIMALSEPARATOR', ('USB', 0xB3) ), ( 'DECIMAL SEPARATOR', ('USB', 0xB3) ), + ( 'CURRENCY', ('USB', 0xB4) ), ( 'CURRENCYUNIT', ('USB', 0xB4) ), ( 'CURRENCY UNIT', ('USB', 0xB4) ), + ( 'CURRENCYSUB', ('USB', 0xB5) ), ( 'CURRENCYSUBUNIT', ('USB', 0xB5) ), ( 'CURRENCY SUB UNIT', ('USB', 0xB5) ), + ( 'P(', ('USB', 0xB6) ), ( 'KEYPAD LEFT PARENTHESES', ('USB', 0xB6) ), + ( 'P)', ('USB', 0xB7) ), ( 'KEYPAD RIGHT PARENTHESES', ('USB', 0xB7) ), + ( 'P{', ('USB', 0xB8) ), ( 'KEYPAD LEFT BRACE', ('USB', 0xB8) ), + ( 'P}', ('USB', 0xB9) ), ( 'KEYPAD RIGHT BRACE', ('USB', 0xB9) ), + ( 'PTAB', ('USB', 0xBA) ), ( 'KEYPAD TAB', ('USB', 0xBA) ), + ( 'PBACKSPACE', ('USB', 0xBB) ), ( 'KEYPAD BACKSPACE', ('USB', 0xBB) ), + ( 'PA', ('USB', 0xBC) ), ( 'KEYPAD A', ('USB', 0xBC) ), + ( 'PB', ('USB', 0xBD) ), ( 'KEYPAD B', ('USB', 0xBD) ), + ( 'PC', ('USB', 0xBE) ), ( 'KEYPAD C', ('USB', 0xBE) ), + ( 'PD', ('USB', 0xBF) ), ( 'KEYPAD D', ('USB', 0xBF) ), + ( 'PE', ('USB', 0xC0) ), ( 'KEYPAD E', ('USB', 0xC0) ), + ( 'PF', ('USB', 0xC1) ), ( 'KEYPAD F', ('USB', 0xC1) ), + ( 'PXOR', ('USB', 0xC2) ), ( 'KEYPAD XOR', ('USB', 0xC2) ), + ( 'P^', ('USB', 0xC3) ), ( 'KEYPAD CHEVRON', ('USB', 0xC3) ), + ( 'P%', ('USB', 0xC4) ), ( 'KEYPAD PERCENT', ('USB', 0xC4) ), + ( 'P<', ('USB', 0xC5) ), ( 'KEYPAD LESSTHAN', ('USB', 0xC5) ), ( 'KEYPAD LESS THAN', ('USB', 0xC5) ), + ( 'P>', ('USB', 0xC6) ), ( 'KEYPAD GREATERTHAN', ('USB', 0xC6) ), ( 'KEYPAD GREATER THAN', ('USB', 0xC6) ), + ( 'P&', ('USB', 0xC7) ), ( 'KEYPAD BITAND', ('USB', 0xC7) ), ( 'KEYPAD BIT AND', ('USB', 0xC7) ), + ( 'P&&', ('USB', 0xC8) ), ( 'KEYPAD AND', ('USB', 0xC8) ), + ( 'P|', ('USB', 0xC9) ), ( 'KEYPAD BITOR', ('USB', 0xC9) ), ( 'KEYPAD BIT OR', ('USB', 0xC9) ), + ( 'P||', ('USB', 0xCA) ), ( 'KEYPAD OR', ('USB', 0xCA) ), + ( 'P:', ('USB', 0xCB) ), ( 'KEYPAD COLON', ('USB', 0xCB) ), + ( 'P#', ('USB', 0xCC) ), ( 'KEYPAD NUMBER', ('USB', 0xCC) ), ( 'KEYPAD HASH', ('USB', 0xCC) ), + ( 'PSPACE', ('USB', 0xCD) ), ( 'KEYPAD SPACE', ('USB', 0xCD) ), + ( 'P@', ('USB', 0xCE) ), ( 'KEYPAD AT', ('USB', 0xCE) ), + ( 'P!', ('USB', 0xCF) ), ( 'KEYPAD EXCLAIM', ('USB', 0xCF) ), + ( 'PMEMSTORE', ('USB', 0xD0) ), ( 'KEYPAD MEMSTORE', ('USB', 0xD0) ), ( 'KEYPAD MEMORY STORE', ('USB', 0xD0) ), + ( 'PMEMRECALL', ('USB', 0xD1) ), ( 'KEYPAD MEMRECALL', ('USB', 0xD1) ), ( 'KEYPAD MEMORY RECALL', ('USB', 0xD1) ), + ( 'PMEMCLEAR', ('USB', 0xD2) ), ( 'KEYPAD MEMCLEAR', ('USB', 0xD2) ), ( 'KEYPAD MEMORY CLEAR', ('USB', 0xD2) ), + ( 'PMEMADD', ('USB', 0xD3) ), ( 'KEYPAD MEMADD', ('USB', 0xD3) ), ( 'KEYPAD MEMORY ADD', ('USB', 0xD3) ), + ( 'PMEMSUB', ('USB', 0xD4) ), ( 'KEYPAD MEMSUB', ('USB', 0xD4) ), ( 'KEYPAD MEMORY SUB', ('USB', 0xD4) ), + ( 'PMEMMULT', ('USB', 0xD5) ), ( 'KEYPAD MEMMULT', ('USB', 0xD5) ), ( 'KEYPAD MEMORY MULTIPLY', ('USB', 0xD5) ), + ( 'PMEMDIV', ('USB', 0xD6) ), ( 'KEYPAD MEMDIV', ('USB', 0xD6) ), ( 'KEYPAD MEMORY DIVIDE', ('USB', 0xD6) ), + ( 'P+/-', ('USB', 0xD7) ), ( 'KEYPAD PLUSMINUS', ('USB', 0xD7) ), ( 'KEYPAD PLUS MINUS', ('USB', 0xD7) ), + ( 'PCLEAR', ('USB', 0xD8) ), ( 'KEYPAD CLEAR', ('USB', 0xD8) ), + ( 'PCLEARENTRY', ('USB', 0xD9) ), ( 'KEYPAD CLEARENTRY', ('USB', 0xD9) ), ( 'KEYPAD CLEAR ENTRY', ('USB', 0xD9) ), + ( 'PBINARY', ('USB', 0xDA) ), ( 'KEYPAD BINARY', ('USB', 0xDA) ), + ( 'POCTAL', ('USB', 0xDB) ), ( 'KEYPAD OCTAL', ('USB', 0xDB) ), + ( 'PDECIMAL', ('USB', 0xDC) ), ( 'KEYPAD DECIMAL', ('USB', 0xDC) ), + ( 'PHEX', ('USB', 0xDD) ), ( 'KEYPAD HEX', ('USB', 0xDD) ), + + ( 'LCTRL', ('USB', 0xE0) ), ( 'LEFT CTRL', ('USB', 0xE0) ), ( 'CTRL', ('USB', 0xE0) ), ( 'CONTROL', ('USB', 0xE0) ), ( 'LEFT CONTROL', ('USB', 0xE0) ), + ( 'LSHIFT', ('USB', 0xE1) ), ( 'LEFT SHIFT', ('USB', 0xE1) ), ( 'SHIFT', ('USB', 0xE1) ), + ( 'LALT', ('USB', 0xE2) ), ( 'LEFT ALT', ('USB', 0xE2) ), ( 'ALT', ('USB', 0xE2) ), ( 'ALTERNATE', ('USB', 0xE2) ), ( 'LEFT ALTERNATE', ('USB', 0xE2) ), + ( 'LGUI', ('USB', 0xE3) ), ( 'LEFT GUI', ('USB', 0xE3) ), ( 'GUI', ('USB', 0xE3) ), ( 'SUPER', ('USB', 0xE3) ), ( 'LEFT SUPER', ('USB', 0xE3) ), ( 'WINDOWS', ('USB', 0xE3) ), ( 'LEFT WINDOWS', ('USB', 0xE3) ), ( 'WIN', ('USB', 0xE3) ), ( 'LEFT WIN', ('USB', 0xE3) ), + ( 'RCTRL', ('USB', 0xE4) ), ( 'RIGHT CTRL', ('USB', 0xE4) ), ( 'RIGHT CONTROL', ('USB', 0xE4) ), + ( 'RSHIFT', ('USB', 0xE5) ), ( 'RIGHT SHIFT', ('USB', 0xE5) ), + ( 'RALT', ('USB', 0xE6) ), ( 'RIGHT ALT', ('USB', 0xE6) ), ( 'RIGHT ALTERNATE', ('USB', 0xE6) ), + ( 'RGUI', ('USB', 0xE7) ), ( 'RIGHT GUI', ('USB', 0xE7) ), ( 'RIGHT SUPER', ('USB', 0xE7) ), ( 'RIGHT WINDOWS', ('USB', 0xE7) ), ( 'RIGHT WIN', ('USB', 0xE7) ), + +# Special Function Shift/Lock/Latch symbolic names (not part of the USB HID spec) + ( 'FUN1', ('USB', 0xF0) ), ( 'FUNCTION1', ('USB', 0xF0) ), ( 'FUN', ('USB', 0xF0) ), + ( 'FUN2', ('USB', 0xF1) ), ( 'FUNCTION2', ('USB', 0xF1) ), + ( 'FUN3', ('USB', 0xF2) ), ( 'FUNCTION3', ('USB', 0xF2) ), + ( 'FUN4', ('USB', 0xF3) ), ( 'FUNCTION4', ('USB', 0xF3) ), + ( 'FUN5', ('USB', 0xF4) ), ( 'FUNCTION5', ('USB', 0xF4) ), + ( 'FUN6', ('USB', 0xF5) ), ( 'FUNCTION6', ('USB', 0xF5) ), + ( 'FUN7', ('USB', 0xF6) ), ( 'FUNCTION7', ('USB', 0xF6) ), + ( 'FUN8', ('USB', 0xF7) ), ( 'FUNCTION8', ('USB', 0xF7) ), + ( 'FUN9', ('USB', 0xF8) ), ( 'FUNCTION9', ('USB', 0xF8) ), + ( 'FUN10', ('USB', 0xF9) ), ( 'FUNCTION10', ('USB', 0xF9) ), + ( 'FUN11', ('USB', 0xFA) ), ( 'FUNCTION11', ('USB', 0xFA) ), + ( 'FUN12', ('USB', 0xFB) ), ( 'FUNCTION12', ('USB', 0xFB) ), + ( 'FUN13', ('USB', 0xFC) ), ( 'FUNCTION13', ('USB', 0xFC) ), + ( 'FUN14', ('USB', 0xFD) ), ( 'FUNCTION14', ('USB', 0xFD) ), + ( 'FUN15', ('USB', 0xFE) ), ( 'FUNCTION15', ('USB', 0xFE) ), + ( 'FUN16', ('USB', 0xFF) ), ( 'FUNCTION16', ('USB', 0xFF) ), + ( 'LCK1', ('USB', 0x100) ), ( 'LOCK1', ('USB', 0x100) ), ( 'LCK', ('USB', 0x100) ), + ( 'LCK2', ('USB', 0x101) ), ( 'LOCK2', ('USB', 0x101) ), + ( 'LCK3', ('USB', 0x102) ), ( 'LOCK3', ('USB', 0x102) ), + ( 'LCK4', ('USB', 0x103) ), ( 'LOCK4', ('USB', 0x103) ), + ( 'LCK5', ('USB', 0x104) ), ( 'LOCK5', ('USB', 0x104) ), + ( 'LCK6', ('USB', 0x105) ), ( 'LOCK6', ('USB', 0x105) ), + ( 'LCK7', ('USB', 0x106) ), ( 'LOCK7', ('USB', 0x106) ), + ( 'LCK8', ('USB', 0x107) ), ( 'LOCK8', ('USB', 0x107) ), + ( 'LCK9', ('USB', 0x108) ), ( 'LOCK9', ('USB', 0x108) ), + ( 'LCK10', ('USB', 0x109) ), ( 'LOCK10', ('USB', 0x109) ), + ( 'LCK11', ('USB', 0x10A) ), ( 'LOCK11', ('USB', 0x10A) ), + ( 'LCK12', ('USB', 0x10B) ), ( 'LOCK12', ('USB', 0x10B) ), + ( 'LCK13', ('USB', 0x10C) ), ( 'LOCK13', ('USB', 0x10C) ), + ( 'LCK14', ('USB', 0x10D) ), ( 'LOCK14', ('USB', 0x10D) ), + ( 'LCK15', ('USB', 0x10E) ), ( 'LOCK15', ('USB', 0x10E) ), + ( 'LCK16', ('USB', 0x10F) ), ( 'LOCK16', ('USB', 0x10F) ), + ( 'LAT1', ('USB', 0x110) ), ( 'LATCH1', ('USB', 0x110) ), ( 'LAT', ('USB', 0x110) ), + ( 'LAT2', ('USB', 0x111) ), ( 'LATCH2', ('USB', 0x111) ), + ( 'LAT3', ('USB', 0x112) ), ( 'LATCH3', ('USB', 0x112) ), + ( 'LAT4', ('USB', 0x113) ), ( 'LATCH4', ('USB', 0x113) ), + ( 'LAT5', ('USB', 0x114) ), ( 'LATCH5', ('USB', 0x114) ), + ( 'LAT6', ('USB', 0x115) ), ( 'LATCH6', ('USB', 0x115) ), + ( 'LAT7', ('USB', 0x116) ), ( 'LATCH7', ('USB', 0x116) ), + ( 'LAT8', ('USB', 0x117) ), ( 'LATCH8', ('USB', 0x117) ), + ( 'LAT9', ('USB', 0x118) ), ( 'LATCH9', ('USB', 0x118) ), + ( 'LAT10', ('USB', 0x119) ), ( 'LATCH10', ('USB', 0x119) ), + ( 'LAT11', ('USB', 0x11A) ), ( 'LATCH11', ('USB', 0x11A) ), + ( 'LAT12', ('USB', 0x11B) ), ( 'LATCH12', ('USB', 0x11B) ), + ( 'LAT13', ('USB', 0x11C) ), ( 'LATCH13', ('USB', 0x11C) ), + ( 'LAT14', ('USB', 0x11D) ), ( 'LATCH14', ('USB', 0x11D) ), + ( 'LAT15', ('USB', 0x11E) ), ( 'LATCH15', ('USB', 0x11E) ), + ( 'LAT16', ('USB', 0x11F) ), ( 'LATCH16', ('USB', 0x11F) ), + ( 'NLAYER', ('USB', 0x120) ), ( 'NEXT LAYER', ('USB', 0x120) ), + ( 'PLAYER', ('USB', 0x121) ), ( 'PREV LAYER', ('USB', 0x121) ), +]) + + + # USB HID LED Codes +kll_hid_lookup_dictionary['IndCode'] = dict([ + ( 'UNDEFINED', ('IND', 0x00) ), + ( 'NUMLOCK', ('IND', 0x01) ), + ( 'CAPSLOCK', ('IND', 0x02) ), + ( 'SCROLLLOCK', ('IND', 0x03) ), + ( 'COMPOSE', ('IND', 0x04) ), + ( 'KANA', ('IND', 0x05) ), + ( 'POWER', ('IND', 0x06) ), + ( 'SHIFT', ('IND', 0x07) ), + ( 'DONOT_DISTURB', ('IND', 0x08) ), + ( 'MUTE', ('IND', 0x09) ), + ( 'TONEENABLE', ('IND', 0x0A) ), + ( 'HIGHCUTFILTER', ('IND', 0x0B) ), + ( 'LOWCUTFILTER', ('IND', 0x0C) ), + ( 'EQLENABLE', ('IND', 0x0D) ), + ( 'SNDFLD_ON', ('IND', 0x0E) ), + ( 'SURROUNDON', ('IND', 0x0F) ), + ( 'REPEAT', ('IND', 0x10) ), + ( 'STEREO', ('IND', 0x11) ), + ( 'SAMPLERT_DET', ('IND', 0x12) ), + ( 'SPINNING', ('IND', 0x13) ), + ( 'CAV', ('IND', 0x14) ), + ( 'CLV', ('IND', 0x15) ), + ( 'RECFMT_DET', ('IND', 0x16) ), + ( 'OFFHOOK', ('IND', 0x17) ), + ( 'RING', ('IND', 0x18) ), + ( 'MSGWAITING', ('IND', 0x19) ), + ( 'DATAMODE', ('IND', 0x1A) ), + ( 'BATOPERATION', ('IND', 0x1B) ), + ( 'BATOK', ('IND', 0x1C) ), + ( 'BATLOW', ('IND', 0x1D) ), + ( 'SPEAKER', ('IND', 0x1E) ), + ( 'HEADSET', ('IND', 0x1F) ), + ( 'HOLD', ('IND', 0x20) ), + ( 'MICROPHONE', ('IND', 0x21) ), + ( 'COVERAGE', ('IND', 0x22) ), + ( 'NIGHTMODE', ('IND', 0x23) ), + ( 'SENDCALLS', ('IND', 0x24) ), + ( 'CALLPICKUP', ('IND', 0x25) ), + ( 'CONFERENCE', ('IND', 0x26) ), + ( 'STANDBY', ('IND', 0x27) ), + ( 'CAMERAON', ('IND', 0x28) ), + ( 'CAMERAOFF', ('IND', 0x29) ), + ( 'ONLINE', ('IND', 0x2A) ), + ( 'OFFLINE', ('IND', 0x2B) ), + ( 'BUSY', ('IND', 0x2C) ), + ( 'READY', ('IND', 0x2D) ), + ( 'PAPEROUT', ('IND', 0x2E) ), + ( 'PAPERJAM', ('IND', 0x2F) ), + ( 'REMOTE', ('IND', 0x30) ), + ( 'FORWARD', ('IND', 0x31) ), + ( 'REVERSE', ('IND', 0x32) ), + ( 'STOP', ('IND', 0x33) ), + ( 'REWIND', ('IND', 0x34) ), + ( 'FASTFORWARD', ('IND', 0x35) ), + ( 'PLAY', ('IND', 0x36) ), + ( 'PAUSE', ('IND', 0x37) ), + ( 'RECORD', ('IND', 0x38) ), + ( 'ERROR', ('IND', 0x39) ), + ( 'USI', ('IND', 0x3A) ), + ( 'UIUI', ('IND', 0x3B) ), + ( 'UMMI', ('IND', 0x3C) ), + ( 'INDON', ('IND', 0x3D) ), + ( 'INDFLASH', ('IND', 0x3E) ), + ( 'INDSLOW_BLNK', ('IND', 0x3F) ), + ( 'INDFAST_BLNK', ('IND', 0x40) ), + ( 'INDOFF', ('IND', 0x41) ), + ( 'FLASHON_TIME', ('IND', 0x42) ), + ( 'SLWB_ON_TIME', ('IND', 0x43) ), + ( 'SLWB_OFF_TIME', ('IND', 0x44) ), + ( 'FSTB_ON_TIME', ('IND', 0x45) ), + ( 'FSTB_OFF_TIME', ('IND', 0x46) ), + ( 'UIC', ('IND', 0x47) ), + ( 'INDRED', ('IND', 0x48) ), + ( 'INDGREEN', ('IND', 0x49) ), + ( 'INDAMBER', ('IND', 0x4A) ), + ( 'GENERICIND', ('IND', 0x4B) ), + ( 'SYSSUSPEND', ('IND', 0x4C) ), + ( 'EXTPWR_CONN', ('IND', 0x4D) ), +# 0x4E - 0xFFFF Reserved +]) + + +# List of System Controls - USB HID 1.12v2 pg 32 +# NKRO HID Supports 0x81 - 0xB7 +kll_hid_lookup_dictionary['SysCode'] = dict([ + ( 'POWERDOWN', ('SYS', 0x81) ), + ( 'SLEEP', ('SYS', 0x82) ), + ( 'WAKEUP', ('SYS', 0x83) ), + ( 'CONTEXTMENU', ('SYS', 0x84) ), + ( 'MAINMENU', ('SYS', 0x85) ), + ( 'APPMENU', ('SYS', 0x86) ), + ( 'MENUHELP', ('SYS', 0x87) ), + ( 'MENUEXIT', ('SYS', 0x88) ), + ( 'MENUSELECT', ('SYS', 0x89) ), + ( 'MENURIGHT', ('SYS', 0x8A) ), + ( 'MENULEFT', ('SYS', 0x8B) ), + ( 'MENUUP', ('SYS', 0x8C) ), + ( 'MENUDOWN', ('SYS', 0x8D) ), + ( 'COLDRESTART', ('SYS', 0x8E) ), + ( 'WARMRESTART', ('SYS', 0x8F) ), + ( 'DPADUP', ('SYS', 0x90) ), + ( 'DPADDOWN', ('SYS', 0x91) ), + ( 'DPADRIGHT', ('SYS', 0x92) ), + ( 'DPADLEFT', ('SYS', 0x93) ), +# 0x94 - 0x9F Reserved + ( 'DOCK', ('SYS', 0xA0) ), + ( 'UNDOCK', ('SYS', 0xA1) ), + ( 'SETUP', ('SYS', 0xA2) ), + ( 'BREAK', ('SYS', 0xA3) ), + ( 'DEBUGGERBREAK', ('SYS', 0xA4) ), + ( 'APPBREAK', ('SYS', 0xA5) ), + ( 'APPDEBUGGER_BREAK', ('SYS', 0xA6) ), + ( 'SPEAKERMUTE', ('SYS', 0xA7) ), + ( 'HIBERNATE', ('SYS', 0xA8) ), +# 0xA9 - 0xAF Reserved + ( 'DISPINVERT', ('SYS', 0xB0) ), + ( 'DISPINTERNAL', ('SYS', 0xB1) ), + ( 'DISPEXTERNAL', ('SYS', 0xB2) ), + ( 'DISPBOTH', ('SYS', 0xB3) ), + ( 'DISPDUAL', ('SYS', 0xB4) ), + ( 'DISPTOGGLE_INT_EXT', ('SYS', 0xB5) ), + ( 'DISPSWAP_PRI_SEC', ('SYS', 0xB6) ), + ( 'DISPLCD_AUTOSCALE', ('SYS', 0xB7) ), +# 0xB8 - 0xFFFF Reserved +]) + + + # USB HID Consumer Control Codes +# List of Consumer Codes - USB HID 1.12v2 +# Only listing relevant ones, let me know if you need more -HaaTa +# NKRO HID Supports 0x020 - 0x29C +kll_hid_lookup_dictionary['ConsCode'] = dict([ + ( '10', ('CONS', 0x020) ), + ( '100', ('CONS', 0x021) ), + ( 'AMPM', ('CONS', 0x022) ), +# 0x023 - 0x03F Reserved + ( 'POWER', ('CONS', 0x030) ), + ( 'RESET', ('CONS', 0x031) ), + ( 'SLEEP', ('CONS', 0x032) ), + ( 'SLEEPAFTER', ('CONS', 0x033) ), + ( 'SLEEPMODE', ('CONS', 0x034) ), + ( 'ILLUMINATION', ('CONS', 0x035) ), + +# 0x037 - 0x03F Reserved + ( 'MENU', ('CONS', 0x040) ), + ( 'MENUPICK', ('CONS', 0x041) ), + ( 'MENUUP', ('CONS', 0x042) ), + ( 'MENUDOWN', ('CONS', 0x043) ), + ( 'MENULEFT', ('CONS', 0x044) ), + ( 'MENURIGHT', ('CONS', 0x045) ), + ( 'MENUESCAPE', ('CONS', 0x046) ), + ( 'MENUVALUE_INCREASE', ('CONS', 0x047) ), + ( 'MENUVALUE_DECREASE', ('CONS', 0x048) ), +# 0x049 - 0x05F Reserved + ( 'DATAON_SCREEN', ('CONS', 0x060) ), + ( 'CLOSEDCAPTION', ('CONS', 0x061) ), + ( 'CLOSEDCAPTION_SELECT', ('CONS', 0x062) ), + ( 'VCRTV', ('CONS', 0x063) ), + ( 'BROADCASTMODE', ('CONS', 0x064) ), + ( 'SNAPSHOT', ('CONS', 0x065) ), + ( 'STILL', ('CONS', 0x066) ), +# 0x067 - 0x06E Reserved? + ( 'BRIGHTNESSINCREMENT', ('CONS', 0x06F) ), + ( 'BRIGHTNESSDECREMENT', ('CONS', 0x070) ), + + ( 'BACKLIGHTTOGGLE', ('CONS', 0x072) ), + ( 'BRIGHTNESSMIN', ('CONS', 0x073) ), + ( 'BRIGHTNESSMAX', ('CONS', 0x074) ), + ( 'BRIGHTNESSAUTO', ('CONS', 0x075) ), +# 0x076 - 0x07F Reserved + + ( 'ASSIGNSELECTION', ('CONS', 0x081) ), + ( 'MODESTEP', ('CONS', 0x082) ), + ( 'RECALLLAST', ('CONS', 0x083) ), + ( 'ENTERCHANNEL', ('CONS', 0x084) ), + ( 'ORDERMOVIE', ('CONS', 0x085) ), + + ( 'MEDIACOMPUTER', ('CONS', 0x088) ), + ( 'MEDIATV', ('CONS', 0x089) ), + ( 'MEDIAWWW', ('CONS', 0x08A) ), + ( 'MEDIADVD', ('CONS', 0x08B) ), + ( 'MEDIATELEPHONE', ('CONS', 0x08C) ), + ( 'MEDIAPROGRAM_GUIDE', ('CONS', 0x08D) ), + ( 'MEDIAVIDEO_PHONE', ('CONS', 0x08E) ), + ( 'MEDIASELECTGAMES', ('CONS', 0x08F) ), + ( 'MEDIASELECTMESSAGES', ('CONS', 0x090) ), + ( 'MEDIASELECTCD', ('CONS', 0x091) ), + ( 'MEDIASELECTVCR', ('CONS', 0x092) ), + ( 'MEDIASELECTTUNER', ('CONS', 0x093) ), + ( 'QUIT', ('CONS', 0x094) ), + ( 'HELP', ('CONS', 0x095) ), + ( 'MEDIASELECT_TAPE', ('CONS', 0x096) ), + ( 'MEDIASELECT_CABLE', ('CONS', 0x097) ), + ( 'MEDIASELECT_SATELLITE', ('CONS', 0x098) ), + ( 'MEDIASELECT_SECURITY', ('CONS', 0x099) ), + ( 'MEDIASELECT_HOME', ('CONS', 0x09A) ), + ( 'MEDIASELECT_CALL', ('CONS', 0x09B) ), + ( 'CHANNELINCREMENT', ('CONS', 0x09C) ), + ( 'CAHNNELDECREMENT', ('CONS', 0x09D) ), + ( 'MEDIASELECT_SAP', ('CONS', 0x09E) ), +# 0x09F Reserved + ( 'VCRPLUS', ('CONS', 0x0A0) ), + ( 'ONCE', ('CONS', 0x0A1) ), + ( 'DAILY', ('CONS', 0x0A2) ), + ( 'WEEKLY', ('CONS', 0x0A3) ), + ( 'MONTHLY', ('CONS', 0x0A4) ), +# 0x0A5 - 0x0AF Reserved + ( 'PLAY', ('CONS', 0x0B0) ), + ( 'PAUSE', ('CONS', 0x0B1) ), + ( 'RECORD', ('CONS', 0x0B2) ), + ( 'FASTFORWARD', ('CONS', 0x0B3) ), + ( 'REWIND', ('CONS', 0x0B4) ), + ( 'SCANNEXTTRACK', ('CONS', 0x0B5) ), + ( 'SCANPREVIOUSTRACK', ('CONS', 0x0B6) ), + ( 'STOP', ('CONS', 0x0B7) ), + ( 'EJECT', ('CONS', 0x0B8) ), + ( 'RANDOMPLAY', ('CONS', 0x0B9) ), + + ( 'REPEAT', ('CONS', 0x0BC) ), + + ( 'TRACKNORMAL', ('CONS', 0x0BE) ), + + ( 'FRAMEFORWARD', ('CONS', 0x0C0) ), + ( 'FRAMEBACK', ('CONS', 0x0C1) ), + ( 'MARK', ('CONS', 0x0C2) ), + ( 'CLEARMARK', ('CONS', 0x0C3) ), + ( 'REPEATFROM_MARK', ('CONS', 0x0C4) ), + ( 'RETURNTO_MARK', ('CONS', 0x0C5) ), + ( 'SEARCHMARK_FORWARDS', ('CONS', 0x0C6) ), + ( 'SEARCHMARK_BACKWARDS', ('CONS', 0x0C7) ), + ( 'COUNTERRESET', ('CONS', 0x0C8) ), + ( 'SHOWCOUNTER', ('CONS', 0x0C9) ), + ( 'TRACKINGINCREMENT', ('CONS', 0x0CA) ), + ( 'TRACKINGDECREMENT', ('CONS', 0x0CB) ), + ( 'STOPEJECT', ('CONS', 0x0CC) ), + ( 'PAUSEPLAY', ('CONS', 0x0CD) ), + ( 'PLAYSKIP', ('CONS', 0x0CE) ), +# 0x0CF - 0x0DF Reserved + + ( 'MUTE', ('CONS', 0x0E2) ), + + ( 'BASSBOOST', ('CONS', 0x0E5) ), + ( 'SURROUNDMODE', ('CONS', 0x0E6) ), + ( 'LOUDNESS', ('CONS', 0x0E7) ), + ( 'MPX', ('CONS', 0x0E8) ), + ( 'VOLUMEUP', ('CONS', 0x0E9) ), + ( 'VOLUMEDOWN', ('CONS', 0x0EA) ), +# 0x0EB - 0x0EF Reserved + ( 'SPEEDSELECT', ('CONS', 0x0F0) ), + ( 'STANDARDPLAY', ('CONS', 0x0F2) ), + ( 'LONGPLAY', ('CONS', 0x0F3) ), + ( 'EXTENDEDPLAY', ('CONS', 0x0F4) ), + ( 'SLOW', ('CONS', 0x0F5) ), +# 0x0F6 - 0x0FF + ( 'FANENABLE', ('CONS', 0x100) ), + + ( 'LIGHTENABLE', ('CONS', 0x102) ), + + ( 'CLIMATECONTROL_ENABLE', ('CONS', 0x104) ), + + ( 'SECURITYENABLE', ('CONS', 0x106) ), + ( 'FIREALARM', ('CONS', 0x107) ), + + ( 'MOTION', ('CONS', 0x10A) ), + ( 'DURESSALARM', ('CONS', 0x10B) ), + ( 'HOLDUPALARM', ('CONS', 0x10C) ), + ( 'MEDICALALARM', ('CONS', 0x10D) ), +# 0x10E - 0x14F Reserved + ( 'BALANCERIGHT', ('CONS', 0x150) ), + ( 'BALANCELEFT', ('CONS', 0x151) ), + ( 'BASSINCR', ('CONS', 0x152) ), + ( 'BASSDECR', ('CONS', 0x153) ), + ( 'TREBLEINCR', ('CONS', 0x154) ), + ( 'TREBLEDECR', ('CONS', 0x155) ), +# 0x156 - 0x15F Reserved + + ( 'SUBCHANNEL_INCREMENT', ('CONS', 0x171) ), + ( 'SUBCHANNEL_DECREMENT', ('CONS', 0x172) ), + ( 'ALTAUDIO_INCREMENT', ('CONS', 0x173) ), + ( 'ALTAUDIO_DECREMENT', ('CONS', 0x174) ), + + +# List of Consumer Codes - USB HID 1.12v2 +# Application Launch Buttons pg 79 + ( 'LAUNCHBUTTON_CONFIG_TOOL', ('CONS', 0x181) ), + ( 'PROGRAMMABLEBUTTON_CONFIG', ('CONS', 0x182) ), + ( 'CONSUMERCONTROL_CONFIG', ('CONS', 0x183) ), + ( 'WORDPROCESSOR', ('CONS', 0x184) ), + ( 'TEXTEDITOR', ('CONS', 0x185) ), + ( 'SPREADSHEET', ('CONS', 0x186) ), + ( 'GRAPHICSEDITOR', ('CONS', 0x187) ), + ( 'PRESENTATIONAPP', ('CONS', 0x188) ), + ( 'DATABASEAPP', ('CONS', 0x189) ), + ( 'EMAILREADER', ('CONS', 0x18A) ), + ( 'NEWSREADER', ('CONS', 0x18B) ), + ( 'VOICEMAIL', ('CONS', 0x18C) ), + ( 'CONTACTSADDRESS_BOOK', ('CONS', 0x18D) ), + ( 'CALENDARSCHEDULE', ('CONS', 0x18E) ), + ( 'TASKPROJECT_MANAGER', ('CONS', 0x18F) ), + ( 'LOGJOURNAL_TIMECARD', ('CONS', 0x190) ), + ( 'CHECKBOOKFINANCE', ('CONS', 0x191) ), + ( 'CALCULATOR', ('CONS', 0x192) ), + ( 'AV_CAPTURE_PLAYBACK', ('CONS', 0x193) ), + ( 'LOCALMACHINE_BROWSER', ('CONS', 0x194) ), + ( 'LANWAN_BROWSER', ('CONS', 0x195) ), + ( 'INTERNETBROWSER', ('CONS', 0x196) ), + ( 'REMOTENETWORKING_ISP_CONNECT', ('CONS', 0x197) ), + ( 'NETWORKCONFERENCE', ('CONS', 0x198) ), + ( 'NETWORKCHAT', ('CONS', 0x199) ), + ( 'TELEPHONYDIALER', ('CONS', 0x19A) ), + ( 'LOGON', ('CONS', 0x19B) ), + ( 'LOGOFF', ('CONS', 0x19C) ), + ( 'LOGONLOGOFF', ('CONS', 0x19D) ), + ( 'TERMINALLOCK_SCREENSAVER', ('CONS', 0x19E) ), + ( 'CONTROLPANEL', ('CONS', 0x19F) ), + ( 'COMMANDLINE_PROCESSOR_RUN', ('CONS', 0x1A0) ), + ( 'PROCESSTASK_MANAGER', ('CONS', 0x1A1) ), + ( 'SELECTTAST_APP', ('CONS', 0x1A2) ), + ( 'NEXTTASK_APP', ('CONS', 0x1A3) ), + ( 'PREVIOUSTASK_APP', ('CONS', 0x1A4) ), + ( 'PREEMPTIVEHALT_TASK_APP', ('CONS', 0x1A5) ), + ( 'INTEGRATEDHELP_CENTER', ('CONS', 0x1A6) ), + ( 'DOCUMENTS', ('CONS', 0x1A7) ), + ( 'THESAURUS', ('CONS', 0x1A8) ), + ( 'DICTIONARY', ('CONS', 0x1A9) ), + ( 'DESKTOP', ('CONS', 0x1AA) ), + ( 'SPELLCHECK', ('CONS', 0x1AB) ), + ( 'GRAMMARCHECK', ('CONS', 0x1AC) ), + ( 'WIRELESSSTATUS', ('CONS', 0x1AD) ), + ( 'KEYBOARDLAYOUT', ('CONS', 0x1AE) ), + ( 'VIRUSPROTECTION', ('CONS', 0x1AF) ), + ( 'ENCRYPTION', ('CONS', 0x1B0) ), + ( 'SCREENSAVER', ('CONS', 0x1B1) ), + ( 'ALARMS', ('CONS', 0x1B2) ), + ( 'CLOCK', ('CONS', 0x1B3) ), + ( 'FILEBROWSER', ('CONS', 0x1B4) ), + ( 'POWERSTATUS', ('CONS', 0x1B5) ), + ( 'IMAGEBROWSER', ('CONS', 0x1B6) ), + ( 'AUDIOBROWSER', ('CONS', 0x1B7) ), + ( 'MOVIEBROWSER', ('CONS', 0x1B8) ), + ( 'DIGITALRIGHTS_MANAGER', ('CONS', 0x1B9) ), + ( 'DIGITALWALLET', ('CONS', 0x1BA) ), +# 0x1BB Reserved + ( 'INSTANTMESSAGING', ('CONS', 0x1BC) ), + ( 'OEMFEATURES_TIPS_TUTORIAL', ('CONS', 0x1BD) ), + ( 'OEMHELP', ('CONS', 0x1BE) ), + ( 'ONLINECOMMUNITY', ('CONS', 0x1BF) ), + ( 'ENTERTAINMENTCONTENT', ('CONS', 0x1C0) ), + ( 'ONLINESHOPPING', ('CONS', 0x1C1) ), + ( 'SMARTCARDINFO_HELP', ('CONS', 0x1C2) ), + ( 'MARKETMONITOR', ('CONS', 0x1C3) ), + ( 'CUSTOMIZEDCORP_NEWS', ('CONS', 0x1C4) ), + ( 'ONLINEACTIVITY', ('CONS', 0x1C5) ), + ( 'SEARCHBROWSER', ('CONS', 0x1C6) ), + ( 'AUDIOPLAYER', ('CONS', 0x1C7) ), + + +# List of Consumer Codes - USB HID 1.12v2 +# Generic GUI Application Controls pg 82 + ( 'NEW', ('CONS', 0x201) ), + ( 'OPEN', ('CONS', 0x202) ), + ( 'CLOSE', ('CONS', 0x203) ), + ( 'EXIT', ('CONS', 0x204) ), + ( 'MAXIMIZE', ('CONS', 0x205) ), + ( 'MINIMIZE', ('CONS', 0x206) ), + ( 'SAVE', ('CONS', 0x207) ), + ( 'PRINT', ('CONS', 0x208) ), + ( 'PROPERTIES', ('CONS', 0x209) ), + ( 'UNDO', ('CONS', 0x21A) ), + ( 'COPY', ('CONS', 0x21B) ), + ( 'CUT', ('CONS', 0x21C) ), + ( 'PASTE', ('CONS', 0x21D) ), + ( 'SELECTALL', ('CONS', 0x21E) ), + ( 'FIND', ('CONS', 0x21F) ), + ( 'FINDANDREPLACE', ('CONS', 0x220) ), + ( 'SEARCH', ('CONS', 0x221) ), + ( 'GOTO', ('CONS', 0x222) ), + ( 'HOME', ('CONS', 0x223) ), + ( 'BACK', ('CONS', 0x224) ), + ( 'FORWARD', ('CONS', 0x225) ), + ( 'STOP', ('CONS', 0x226) ), + ( 'REFRESH', ('CONS', 0x227) ), + ( 'PREVIOUSLINK', ('CONS', 0x228) ), + ( 'NEXTLINK', ('CONS', 0x229) ), + ( 'BOOKMARKS', ('CONS', 0x22A) ), + ( 'HISTORY', ('CONS', 0x22B) ), + ( 'SUBSCRIPTIONS', ('CONS', 0x22C) ), + ( 'ZOOMIN', ('CONS', 0x22D) ), + ( 'ZOOMOUT', ('CONS', 0x22E) ), + ( 'ZOOM', ('CONS', 0x22F) ), + ( 'FULLSCREEN_VIEW', ('CONS', 0x230) ), + ( 'NORMALVIEW', ('CONS', 0x231) ), + ( 'VIEWTOGGLE', ('CONS', 0x232) ), + ( 'SCROLLUP', ('CONS', 0x233) ), + ( 'SCROLLDOWN', ('CONS', 0x234) ), + ( 'SCROLL', ('CONS', 0x235) ), + ( 'PANLEFT', ('CONS', 0x236) ), + ( 'PANRIGHT', ('CONS', 0x237) ), + ( 'PAN', ('CONS', 0x238) ), + ( 'NEWWINDOW', ('CONS', 0x239) ), + ( 'TILEHORIZONTALLY', ('CONS', 0x23A) ), + ( 'TILEVERTICALLY', ('CONS', 0x23B) ), + ( 'FORMAT', ('CONS', 0x23C) ), + ( 'EDIT', ('CONS', 0x23D) ), + ( 'BOLD', ('CONS', 0x23E) ), + ( 'ITALICS', ('CONS', 0x23F) ), + ( 'UNDERLINE', ('CONS', 0x240) ), + ( 'STRIKETHROUGH', ('CONS', 0x241) ), + ( 'SUBSCRIPT', ('CONS', 0x242) ), + ( 'SUPERSCRIPT', ('CONS', 0x243) ), + ( 'ALLCAPS', ('CONS', 0x244) ), + ( 'ROTATE', ('CONS', 0x245) ), + ( 'RESIZE', ('CONS', 0x246) ), + ( 'FILPHORIZONTAL', ('CONS', 0x247) ), + ( 'FILPVERTICAL', ('CONS', 0x248) ), + ( 'MIRRORHORIZONTAL', ('CONS', 0x249) ), + ( 'MIRRORVERTICAL', ('CONS', 0x24A) ), + ( 'FONTSELECT', ('CONS', 0x24B) ), + ( 'FONTCOLOR', ('CONS', 0x24C) ), + ( 'FONTSIZE', ('CONS', 0x24D) ), + ( 'JUSTIFYLEFT', ('CONS', 0x24E) ), + ( 'JUSTIFYCENTER_H', ('CONS', 0x24F) ), + ( 'JUSTIFYRIGHT', ('CONS', 0x250) ), + ( 'JUSTIFYBLOCK_H', ('CONS', 0x251) ), + ( 'JUSTIFYTOP', ('CONS', 0x252) ), + ( 'JUSTIFYCENTER_V', ('CONS', 0x253) ), + ( 'JUSTIFYBOTTOM', ('CONS', 0x254) ), + ( 'JUSTIFYBLOCK_V', ('CONS', 0x255) ), + ( 'INDENTDECREASE', ('CONS', 0x256) ), + ( 'INDENTINCREASE', ('CONS', 0x257) ), + ( 'NUMBEREDLIST', ('CONS', 0x258) ), + ( 'RESTARTNUMBERING', ('CONS', 0x259) ), + ( 'BULLETEDLIST', ('CONS', 0x25A) ), + ( 'PROMOTE', ('CONS', 0x25B) ), + ( 'DEMOTE', ('CONS', 0x25C) ), + ( 'YES', ('CONS', 0x25D) ), + ( 'NO', ('CONS', 0x25E) ), + ( 'CANCEL', ('CONS', 0x25F) ), + ( 'CATALOG', ('CONS', 0x260) ), + ( 'BUYCHECKOUT', ('CONS', 0x261) ), + ( 'ADDTO_CART', ('CONS', 0x262) ), + ( 'EXPAND', ('CONS', 0x263) ), + ( 'EXPANDALL', ('CONS', 0x264) ), + ( 'COLLAPSE', ('CONS', 0x265) ), + ( 'COLLAPSEALL', ('CONS', 0x266) ), + ( 'PRINTPREVIEW', ('CONS', 0x267) ), + ( 'PASTESPECIAL', ('CONS', 0x268) ), + ( 'INSERTMODE', ('CONS', 0x269) ), + ( 'DELETE', ('CONS', 0x26A) ), + ( 'LOCK', ('CONS', 0x26B) ), + ( 'UNLOCK', ('CONS', 0x26C) ), + ( 'PROTECT', ('CONS', 0x26D) ), + ( 'UNPROTECT', ('CONS', 0x26E) ), + ( 'ATTACHCOMMENT', ('CONS', 0x26F) ), + ( 'DELETECOMMENT', ('CONS', 0x270) ), + ( 'VIEWCOMMENT', ('CONS', 0x271) ), + ( 'SELECTWORD', ('CONS', 0x272) ), + ( 'SELECTSENTENCE', ('CONS', 0x273) ), + ( 'SELECTPARAGRAPH', ('CONS', 0x274) ), + ( 'SELECTCOLUMN', ('CONS', 0x275) ), + ( 'SELECTROW', ('CONS', 0x276) ), + ( 'SELECTTABLE', ('CONS', 0x277) ), + ( 'SELECTOBJECT', ('CONS', 0x278) ), + ( 'REDOREPEAT', ('CONS', 0x279) ), + ( 'SORT', ('CONS', 0x27A) ), + ( 'SORTASCENDING', ('CONS', 0x27B) ), + ( 'SORTDESCENDING', ('CONS', 0x27C) ), + ( 'FILTER', ('CONS', 0x27D) ), + ( 'SETCLOCK', ('CONS', 0x27E) ), + ( 'VIEWCLOCK', ('CONS', 0x27F) ), + ( 'SELECTTIME_ZONE', ('CONS', 0x280) ), + ( 'EDITTIME_ZONE', ('CONS', 0x281) ), + ( 'SETALARM', ('CONS', 0x282) ), + ( 'CLEARALARM', ('CONS', 0x283) ), + ( 'SNOOZEALARM', ('CONS', 0x284) ), + ( 'RESETALARM', ('CONS', 0x285) ), + ( 'SYNCHRONIZE', ('CONS', 0x286) ), + ( 'SENDRECEIVE', ('CONS', 0x287) ), + ( 'SENDTO', ('CONS', 0x288) ), + ( 'REPLY', ('CONS', 0x289) ), + ( 'REPLYALL', ('CONS', 0x28A) ), + ( 'FORWARDMSG', ('CONS', 0x28B) ), + ( 'SEND', ('CONS', 0x28C) ), + ( 'ATTACHFILE', ('CONS', 0x28D) ), + ( 'UPLOAD', ('CONS', 0x28E) ), + ( 'DOWNLOAD', ('CONS', 0x28F) ), + ( 'SETBORDERS', ('CONS', 0x290) ), + ( 'INSERTROW', ('CONS', 0x291) ), + ( 'INSERTCOLUMN', ('CONS', 0x292) ), + ( 'INSERTFILE', ('CONS', 0x293) ), + ( 'INSERTPICTURE', ('CONS', 0x294) ), + ( 'INSERTOBJECT', ('CONS', 0x295) ), + ( 'INSERTSYMBOL', ('CONS', 0x296) ), + ( 'SAVEANDCLOSE', ('CONS', 0x297) ), + ( 'RENAME', ('CONS', 0x298) ), + ( 'MERGE', ('CONS', 0x299) ), + ( 'SPLIT', ('CONS', 0x29A) ), + ( 'DISTRIBUTEHORIZONTALLY', ('CONS', 0x29B) ), + ( 'DISTRIBUTEVERTICALLY', ('CONS', 0x29C) ), + ( 'NEXTKEYBOARDLAYOUTSELECT', ('CONS', 0x29D) ), +# 0x29E-0xFFFF Reserved +]) + diff --git a/common/id.py b/common/id.py new file mode 100644 index 0000000..3337068 --- /dev/null +++ b/common/id.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +''' +KLL Id Containers +''' + +# Copyright (C) 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 . + +### Imports ### + +from common.hid_dict import hid_lookup_dictionary + +from common.channel import ChannelList +from common.modifier import AnimationModifierList, PixelModifierList +from common.position import Position +from common.schedule import Schedule + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +class Id: + ''' + Base container class for various KLL types + ''' + def __init__( self ): + self.type = None + self.uid = None + + +class HIDId( Id, Schedule ): + ''' + HID/USB identifier container class + ''' + secondary_types = { + 'USBCode' : 'USB', + 'SysCode' : 'SYS', + 'ConsCode' : 'CONS', + 'IndCode' : 'IND', + } + + def __init__( self, type, uid ): + ''' + @param type: String type of the Id + @param uid: Unique integer identifier for the Id + ''' + Id.__init__( self ) + Schedule.__init__( self ) + self.type = type + self.uid = uid + + # Set secondary type + self.second_type = self.secondary_types[ self.type ] + + # TODO Validate uid to make sure it's in the lookup dictionary + # TODO Validate HID specifier + #print ( "{0} Unknown HID Specifier '{1}'".format( ERROR, type ) ) + #raise + + def __repr__( self ): + ''' + Use string name instead of integer, easier to debug + ''' + uid = hid_lookup_dictionary[ ( self.second_type, self.uid ) ] + schedule = self.strSchedule() + if len( schedule ) > 0: + schedule = "({0})".format( schedule ) + + output = 'HID({0})"{1}"{2}'.format( self.type, uid, schedule ) + return output + + +class ScanCodeId( Id, Schedule, Position ): + ''' + Scan Code identifier container class + ''' + + def __init__( self, uid ): + Id.__init__( self ) + Schedule.__init__( self ) + Position.__init__( self ) + self.type = 'ScanCode' + self.uid = uid + + # By default, interconnect_id of 0 + # Will be set during the merge process if it needs to change + self.interconnect_id = 0 + + def unique_key( self ): + ''' + Returns the key string used for datastructure sorting + ''' + # Positions are a special case + if self.positionSet(): + return "P{0}".format( self.uid ) + + def __repr__( self ): + # Positions are a special case + if self.positionSet(): + return "{0} <= {1}".format( self.unique_key(), self.strPosition() ) + + schedule = self.strSchedule() + if len( schedule ) > 0: + return "S{0}({1})".format( self.uid, schedule ) + else: + return "S{0}".format( self.uid ) + + +class AnimationId( Id, AnimationModifierList ): + ''' + Animation identifier container class + ''' + name = None + + def __init__( self, name ): + Id.__init__( self ) + AnimationModifierList.__init__( self ) + self.name = name + self.type = 'Animation' + + def __repr__( self ): + if len( self.modifiers ) > 0: + return "A[{0}]({1})".format( self.name, self.strModifiers() ) + return "A[{0}]".format( self.name ) + + +class AnimationFrameId( Id, AnimationModifierList ): + ''' + Animation Frame identifier container class + ''' + def __init__( self, name, index ): + Id.__init__( self ) + AnimationModifierList.__init__( self ) + self.name = name + self.index = index + self.type = 'AnimationFrame' + + def __repr__( self ): + return "AF[{0}, {1}]".format( self.name, self.index ) + + +class PixelId( Id, Position, PixelModifierList, ChannelList ): + ''' + Pixel identifier container class + ''' + def __init__( self, uid ): + Id.__init__( self ) + Position.__init__( self ) + PixelModifierList.__init__( self ) + ChannelList.__init__( self ) + self.uid = uid + self.type = 'Pixel' + + def unique_key( self ): + ''' + Returns the key string used for datastructure sorting + ''' + return "P{0}".format( self.uid ) + + def __repr__( self ): + # Positions are a special case + if self.positionSet(): + return "{0} <= {1}".format( self.unique_key(), self.strPosition() ) + + extra = "" + if len( self.modifiers ) > 0: + extra += "({0})".format( self.strModifiers() ) + if len( self.channels ) > 0: + extra += "({0})".format( self.strChannels() ) + return "{0}{1}".format( self.unique_key(), extra ) + + +class PixelLayerId( Id, PixelModifierList ): + ''' + Pixel Layer identifier container class + ''' + def __init__( self, uid ): + Id.__init__( self ) + PixelModifierList.__init__( self ) + self.uid = uid + self.type = 'PixelLayer' + + def __repr__( self ): + if len( self.modifiers ) > 0: + return "PL{0}({1})".format( self.uid, self.strModifiers() ) + return "PL{0}".format( self.uid ) + + +class CapId( Id ): + ''' + Capability identifier + ''' + def __init__( self, name, type, arg_list=[] ): + ''' + @param name: Name of capability + @param type: Type of capability definition, string + @param arg_list: List of CapArgIds, empty list if there are none + ''' + Id.__init__( self ) + self.name = name + self.type = type + self.arg_list = arg_list + + def __repr__( self ): + # Generate prettified argument list + arg_string = "" + for arg in self.arg_list: + arg_string += "{0},".format( arg ) + if len( arg_string ) > 0: + arg_string = arg_string[:-1] + + return "{0}({1})".format( self.name, arg_string ) + + def total_arg_bytes( self ): + ''' + Calculate the total number of bytes needed for the args + + return: Number of bytes + ''' + # Zero if no args + total_bytes = 0 + for arg in self.arg_list: + total_bytes += arg.width + + return total_bytes + + +class NoneId( CapId ): + ''' + None identifier + + It's just a capability...that does nothing (instead of infering to do something else) + ''' + def __init__( self ): + super().__init__( 'None', 'None' ) + + def __repr__( self ): + return "None" + + +class CapArgId( Id ): + ''' + Capability Argument identifier + ''' + def __init__( self, name, width=None ): + ''' + @param name: Name of argument + @param width: Byte-width of the argument, if None, this is not port of a capability definition + ''' + Id.__init__( self ) + self.name = name + self.width = width + self.type = 'CapArg' + + def __repr__( self ): + if self.width is None: + return "{0}".format( self.name ) + else: + return "{0}:{1}".format( self.name, self.width ) + diff --git a/common/modifier.py b/common/modifier.py new file mode 100644 index 0000000..4420d2a --- /dev/null +++ b/common/modifier.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +''' +KLL Modifier Containers +''' + +# Copyright (C) 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 . + +### Imports ### + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +class AnimationModifier: + ''' + Animation modification container class + ''' + def __init__( self, name, value=None ): + self.name = name + self.value = value + + def __repr__( self ): + if self.value is None: + return "{0}".format( self.name ) + return "{0}:{1}".format( self.name, self.value ) + + +class AnimationModifierList: + ''' + Animation modification container list class + + Contains a list of modifiers, the order does not matter + ''' + def __init__( self ): + self.modifiers = [] + + def setModifiers( self, modifier_list ): + ''' + Apply modifiers to Animation + ''' + for modifier in modifier_list: + self.modifiers.append( AnimationModifier( modifier[0], modifier[1] ) ) + + def strModifiers( self ): + ''' + __repr__ of Position when multiple inheritance is used + ''' + output = "" + for index, modifier in enumerate( self.modifiers ): + if index > 0: + output += "," + output += "{0}".format( modifier ) + + return output + + def __repr__( self ): + return self.strModifiers() + + +class PixelModifier: + ''' + Pixel modification container class + ''' + def __init__( self, operator, value ): + self.operator = operator + self.value = value + + def __repr__( self ): + if self.operator is None: + return "{0}".format( self.value ) + return "{0}{1}".format( self.operator, self.value ) + + +class PixelModifierList: + ''' + Pixel modification container list class + + Contains a list of modifiers + Index 0, corresponds to pixel 0 + ''' + def __init__( self ): + self.modifiers = [] + + def setModifiers( self, modifier_list ): + ''' + Apply modifier to each pixel channel + ''' + for modifier in modifier_list: + self.modifiers.append( PixelModifier( modifier[0], modifier[1] ) ) + + def strModifiers( self ): + ''' + __repr__ of Position when multiple inheritance is used + ''' + output = "" + for index, modifier in enumerate( self.modifiers ): + if index > 0: + output += "," + output += "{0}".format( modifier ) + + return output + + def __repr__( self ): + return self.strModifiers() + diff --git a/common/organization.py b/common/organization.py new file mode 100644 index 0000000..2d189a3 --- /dev/null +++ b/common/organization.py @@ -0,0 +1,614 @@ +#!/usr/bin/env python3 +''' +KLL Data Organization +''' + +# Copyright (C) 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 . + +### Imports ### + +import re + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + +ansi_escape = re.compile(r'\x1b[^m]*m') + + + +### Classes ### + +class Data: + ''' + Base class for KLL datastructures + ''' + # Debug output formatters + debug_output = { + 'add' : "\t\033[1;42;37m++\033[0m\033[1mADD KEY\033[1;42;37m++\033[0m \033[1m<==\033[0m {0}", + 'app' : "\t\033[1;45;37m**\033[0m\033[1mAPP KEY\033[1;45;37m**\033[0m \033[1m<==\033[0m {0}", + 'mod' : "\t\033[1;44;37m##\033[0m\033[1mMOD KEY\033[1;44;37m##\033[0m \033[1m<==\033[0m {0}", + 'rem' : "\t\033[1;41;37m--\033[0m\033[1mREM KEY\033[1;41;37m--\033[0m \033[1m<==\033[0m {0}", + 'drp' : "\t\033[1;43;37m@@\033[0m\033[1mDRP KEY\033[1;43;37m@@\033[0m \033[1m<==\033[0m {0}", + 'dup' : "\t\033[1;46;37m!!\033[0m\033[1mDUP KEY\033[1;46;37m!!\033[0m \033[1m<==\033[0m {0}", + } + + def __init__( self, parent ): + ''' + Initialize datastructure + + @param parent: Parent organization, used to query data from other datastructures + ''' + self.data = {} + self.parent = parent + + def add_expression( self, expression, debug ): + ''' + Add expression to data structure + + May have multiple keys to add for a given expression + + @param expression: KLL Expression (fully tokenized and parsed) + @param debug: Enable debug output + ''' + # Lookup unique keys for expression + keys = expression.unique_keys() + + # Add/Modify expressions in datastructure + for key, uniq_expr in keys: + # Check which operation we are trying to do, add or modify + if debug[0]: + if key in self.data.keys(): + output = self.debug_output['mod'].format( key ) + else: + output = self.debug_output['add'].format( key ) + print( debug[1] and output or ansi_escape.sub( '', output ) ) + + self.data[ key ] = uniq_expr + + def merge( self, merge_in, debug ): + ''' + Merge in the given datastructure to this datastructure + + This datastructure serves as the base. + + @param merge_in: Data structure from another organization to merge into this one + @param debug: Enable debug out + ''' + # The default case is just to add the expression in directly + for key, kll_expression in merge_in.data.items(): + # Display key:expression being merged in + if debug[0]: + output = merge_in.elem_str( key, True ) + print( debug[1] and output or ansi_escape.sub( '', output ), end="" ) + + self.add_expression( kll_expression, debug ) + + def reduction( self ): + ''' + Simplifies datastructure + + Most of the datastructures don't have a reduction. Just do nothing in this case. + ''' + pass + + def elem_str( self, key, single=False ): + ''' + Debug output for a single element + + @param key: Index to datastructure + @param single: Setting to True will bold the key + ''' + if single: + return "\033[1;33m{0: <20}\033[0m \033[1;36;41m>\033[0m {1}\n".format( key, self.data[ key ] ) + else: + return "{0: <20} \033[1;36;41m>\033[0m {1}\n".format( key, self.data[ key ] ) + + def __repr__( self ): + output = "" + + # Display sorted list of keys, along with the internal value + for key in sorted( self.data ): + output += self.elem_str( key ) + + return output + + +class MappingData( Data ): + ''' + KLL datastructure for data mapping + + ScanCode trigger -> result + USBCode trigger -> result + Animation trigger -> result + ''' + def add_expression( self, expression, debug ): + ''' + Add expression to data structure + + May have multiple keys to add for a given expression + + Map expressions insert into the datastructure according to their operator. + + +Operators+ + : Add/Modify + :+ Append + :- Remove + :: Lazy Add/Modify + + i: Add/Modify + i:+ Append + i:- Remove + i:: Lazy Add/Modify + + The i or isolation operators are stored separately from the main ones. + Each key is pre-pended with an i + + The :: or lazy operators act just like : operators, except that they will be ignore if the evaluation + merge cannot resolve a ScanCode. + + @param expression: KLL Expression (fully tokenized and parsed) + @param debug: Enable debug output + ''' + # Lookup unique keys for expression + keys = expression.unique_keys() + + # Add/Modify expressions in datastructure + for key, uniq_expr in keys: + # Determine which the expression operator + operator = expression.operator + + # Except for the : operator, all others have delayed action + # Meaning, they change behaviour depending on how Contexts are merged + # This means we can't simplify yet + # In addition, :+ and :- are stackable, which means each key has a list of expressions + # We append the operator to differentiate between the different types of delayed operations + key = "{0}{1}".format( operator, key ) + + # Determine if key exists already + exists = key in self.data.keys() + + # Add/Modify + if operator in [':', '::', 'i:', 'i::']: + debug_tag = exists and 'mod' or 'add' + + # Append/Remove + else: + # Check to make sure we haven't already appended expression + # Use the string representation to do the comparison (general purpose) + if exists and "{0}".format( uniq_expr ) in [ "{0}".format( elem ) for elem in self.data[ key ] ]: + debug_tag = 'dup' + + # Append + elif operator in [':+', 'i:+']: + debug_tag = 'app' + + # Remove + else: + debug_tag = 'rem' + + # Debug output + if debug[0]: + output = self.debug_output[ debug_tag ].format( key ) + print( debug[1] and output or ansi_escape.sub( '', output ) ) + + # Don't append if a duplicate + if debug_tag == 'dup': + continue + + # Append, rather than replace + if operator in [':+', ':-', 'i:+', 'i:-']: + if exists: + self.data[ key ].append( uniq_expr ) + + # Create initial list + else: + self.data[ key ] = [ uniq_expr ] + else: + self.data[ key ] = [ uniq_expr ] + + def set_interconnect_id( self, interconnect_id, triggers ): + ''' + Traverses the sequence of combo of identifiers to set the interconnect_id + ''' + for sequence in triggers: + for combo in sequence: + for identifier in combo: + identifier.interconnect_id = interconnect_id + + def merge( self, merge_in, debug ): + ''' + Merge in the given datastructure to this datastructure + + This datastructure serves as the base. + + Map expressions merge differently than insertions. + + +Operators+ + : Add/Modify - Replace + :+ Append - Add + :- Remove - Remove + :: Lazy Add/Modify - Replace if found, otherwise drop + + i: Add/Modify - Replace + i:+ Append - Add + i:- Remove - Remove + i:: Lazy Add/Modify - Replace if found, otherwise drop + + @param merge_in: Data structure from another organization to merge into this one + @param debug: Enable debug out + ''' + # Check what the current interconnectId is + # If not set, we set to 0 (default) + # We use this to calculate the scancode during the DataAnalysisStage + interconnect_id = 0 + if 'interconnectId' in self.parent.variable_data.data.keys(): + interconnect_id = self.parent.variable_data.data['interconnectId'] + + # Sort different types of keys + cur_keys = merge_in.data.keys() + + # Lazy Set :: + lazy_keys = [ key for key in cur_keys if key[0:2] == '::' or key[0:3] == 'i::' ] + cur_keys = list( set( cur_keys ) - set( lazy_keys ) ) + + # Append :+ + append_keys = [ key for key in cur_keys if key[0:2] == ':+' or key[0:3] == 'i:+' ] + cur_keys = list( set( cur_keys ) - set( append_keys ) ) + + # Remove :- + remove_keys = [ key for key in cur_keys if key[0:2] == ':-' or key[0:3] == 'i:-' ] + cur_keys = list( set( cur_keys ) - set( remove_keys ) ) + + # Set : + # Everything left is just a set + set_keys = cur_keys + + + # First process the :: (or lazy) operators + # We need to read into this datastructure and apply those first + # Otherwise we may get undesired behaviour + for key in lazy_keys: + # Display key:expression being merged in + if debug[0]: + output = merge_in.elem_str( key, True ) + print( debug[1] and output or ansi_escape.sub( '', output ), end="" ) + + # Construct target key + target_key = key[0] == 'i' and "i{0}".format( key[2:] ) or key[1:] + + # If target key exists, replace + if target_key in self.data.keys(): + debug_tag = 'mod' + else: + debug_tag = 'drp' + + # Debug output + if debug[0]: + output = self.debug_output[ debug_tag ].format( key ) + print( debug[1] and output or ansi_escape.sub( '', output ) ) + + # Only replace + if debug_tag == 'mod': + self.data[ target_key ] = merge_in.data[ key ] + + # Then apply : assignment operators + for key in set_keys: + # Display key:expression being merged in + if debug[0]: + output = merge_in.elem_str( key, True ) + print( debug[1] and output or ansi_escape.sub( '', output ), end="" ) + + # Construct target key + target_key = key + + # Indicate if add or modify + if target_key in self.data.keys(): + debug_tag = 'mod' + else: + debug_tag = 'add' + + # Debug output + if debug[0]: + output = self.debug_output[ debug_tag ].format( key ) + print( debug[1] and output or ansi_escape.sub( '', output ) ) + + # Set into new datastructure regardless + self.data[ target_key ] = merge_in.data[ key ] + + # Only the : is used to set ScanCodes + # We need to set the interconnect_id just in case the base context has it set + # and in turn influence the new context as well + # This must be done during the merge + for elem in self.data[ target_key ]: + if elem.type == 'ScanCode': + self.set_interconnect_id( interconnect_id, elem.triggers ) + + # Now apply append operations + for key in append_keys: + # Display key:expression being merged in + if debug[0]: + output = merge_in.elem_str( key, True ) + print( debug[1] and output or ansi_escape.sub( '', output ), end="" ) + + # Construct target key + target_key = key[0] == 'i' and "i:{0}".format( key[3:] ) or ":{0}".format( key[2:] ) + + # Alwyays appending + debug_tag = 'app' + + # Debug output + if debug[0]: + output = self.debug_output[ debug_tag ].format( key ) + print( debug[1] and output or ansi_escape.sub( '', output ) ) + + # Extend list if it exists + if target_key in self.data.keys(): + self.data[ target_key ].extend( merge_in.data[ key ] ) + else: + self.data[ target_key ] = merge_in.data[ key ] + + # Finally apply removal operations to this datastructure + # If the target removal doesn't exist, ignore silently (show debug message) + for key in remove_keys: + # Display key:expression being merged in + if debug[0]: + output = merge_in.elem_str( key, True ) + print( debug[1] and output or ansi_escape.sub( '', output ), end="" ) + + # Construct target key + target_key = key[0] == 'i' and "i:{0}".format( key[3:] ) or ":{0}".format( key[2:] ) + + # Drop right away if target datastructure doesn't have target key + if target_key not in self.data.keys(): + debug_tag = 'drp' + + # Debug output + if debug[0]: + output = self.debug_output[ debug_tag ].format( key ) + print( debug[1] and output or ansi_escape.sub( '', output ) ) + + continue + + # Compare expressions to be removed with the current set + # Use strings to compare + remove_expressions = [ "{0}".format( expr ) for expr in merge_in.data[ key ] ] + current_expressions = [ ( "{0}".format( expr ), expr ) for expr in self.data[ target_key ] ] + for string, expr in current_expressions: + debug_tag = 'drp' + + # Check if an expression matches + if string in remove_expressions: + debug_tag = 'rem' + + # Debug output + if debug[0]: + output = self.debug_output[ debug_tag ].format( key ) + print( debug[1] and output or ansi_escape.sub( '', output ) ) + + # Remove if found + if debug_tag == 'rem': + self.data[ target_key ] = [ value for value in self.data.values() if value != expr ] + + def reduction( self ): + ''' + Simplifies datastructure + + Used to replace all trigger HIDCode(USBCode)s with ScanCodes + + NOTE: Make sure to create a new MergeContext before calling this as you lose data and prior context + ''' + scan_code_lookup = {} + + # Build dictionary of single ScanCodes first + for key, expr in self.data.items(): + if expr[0].elems()[0] == 1 and expr[0].triggers[0][0][0].type == 'ScanCode': + scan_code_lookup[ key ] = expr + + # Using this dictionary, replace all the trigger USB codes + new_data = copy.copy( scan_code_lookup ) + + # 1) Single USB Codes trigger results will replace the original ScanCode result + # 2) + + #TODO + print("YAY") + print( scan_code_lookup ) + + +class AnimationData( Data ): + ''' + KLL datastructure for Animation configuration + + Animation -> modifiers + ''' + + +class AnimationFrameData( Data ): + ''' + KLL datastructure for Animation Frame configuration + + Animation -> Pixel Settings + ''' + + +class CapabilityData( Data ): + ''' + KLL datastructure for Capability mapping + + Capability -> C Function/Identifier + ''' + + +class DefineData( Data ): + ''' + KLL datastructure for Define mapping + + Variable -> C Define/Identifier + ''' + + +class PixelChannelData( Data ): + ''' + KLL datastructure for Pixel Channel mapping + + Pixel -> Channels + ''' + + +class PixelPositionData( Data ): + ''' + KLL datastructure for Pixel Position mapping + + Pixel -> Physical Location + ''' + + +class ScanCodePositionData( Data ): + ''' + KLL datastructure for ScanCode Position mapping + + ScanCode -> Physical Location + ''' + + +class VariableData( Data ): + ''' + KLL datastructure for Variables and Arrays + + Variable -> Data + Array -> Data + ''' + + +class Organization: + ''' + Container class for KLL datastructures + + The purpose of these datastructures is to symbolically store at first, and slowly solve/deduplicate expressions. + Since the order in which the merges occurs matters, this involves a number of intermediate steps. + ''' + + def __init__( self ): + ''' + Intialize data structure + ''' + # Setup each of the internal sub-datastructures + self.animation_data = AnimationData( self ) + self.animation_frame_data = AnimationFrameData( self ) + self.capability_data = CapabilityData( self ) + self.define_data = DefineData( self ) + self.mapping_data = MappingData( self ) + self.pixel_channel_data = PixelChannelData( self ) + self.pixel_position_data = PixelPositionData( self ) + self.scan_code_position_data = ScanCodePositionData( self ) + self.variable_data = VariableData( self ) + + # Expression to Datastructure mapping + self.data_mapping = { + 'AssignmentExpression' : { + 'Array' : self.variable_data, + 'Variable' : self.variable_data, + }, + 'DataAssociationExpression' : { + 'Animation' : self.animation_data, + 'AnimationFrame' : self.animation_frame_data, + 'PixelPosition' : self.pixel_position_data, + 'ScanCodePosition' : self.scan_code_position_data, + }, + 'MapExpression' : { + 'ScanCode' : self.mapping_data, + 'USBCode' : self.mapping_data, + 'Animation' : self.mapping_data, + 'PixelChannel' : self.pixel_channel_data, + }, + 'NameAssociationExpression' : { + 'Capability' : self.capability_data, + 'Define' : self.define_data, + }, + } + + def stores( self ): + ''' + Returns list of sub-datastructures + ''' + return [ + self.animation_data, + self.animation_frame_data, + self.capability_data, + self.define_data, + self.mapping_data, + self.pixel_channel_data, + self.pixel_position_data, + self.scan_code_position_data, + self.variable_data, + ] + + def add_expression( self, expression, debug ): + ''' + Add expression to datastructure + + Will automatically determine which type of expression and place in the relevant store + + @param expression: KLL Expression (fully tokenized and parsed) + @param debug: Enable debug output + ''' + # Determine type of of Expression + expression_type = expression.__class__.__name__ + + # Determine Expression Subtype + expression_subtype = expression.type + + # Locate datastructure + data = self.data_mapping[ expression_type ][ expression_subtype ] + + # Debug output + if debug[0]: + output = "\t\033[4m{0}\033[0m".format( data.__class__.__name__ ) + print( debug[1] and output or ansi_escape.sub( '', output ) ) + + # Add expression to determined datastructure + data.add_expression( expression, debug ) + + def merge( self, merge_in, debug ): + ''' + Merge in the given organization to this organization + + This organization serves as the base. + + @param merge_in: Organization to merge into this one + @param debug: Enable debug out + ''' + # Merge each of the sub-datastructures + for this, that in zip( self.stores(), merge_in.stores() ): + this.merge( that, debug ) + + def reduction( self ): + ''' + Simplifies datastructure + + NOTE: This will remove data, therefore, context is lost + ''' + for store in self.stores(): + store.reduction() + + def __repr__( self ): + return "{0}".format( self.stores() ) + diff --git a/common/parse.py b/common/parse.py new file mode 100644 index 0000000..b9ee3f1 --- /dev/null +++ b/common/parse.py @@ -0,0 +1,830 @@ +#!/usr/bin/env python3 +''' +KLL Parsing Expressions + +This file contains various parsing rules and processors used by funcparserlib for KLL + +REMEMBER: When editing parser BNF-like expressions, order matters. Specifically lexer tokens and parser | +''' + +# Parser doesn't play nice with linters, disable some checks +# pylint: disable=no-self-argument, too-many-public-methods, no-self-use, bad-builtin + +# Copyright (C) 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 . + +### Imports ### + +from common.hid_dict import kll_hid_lookup_dictionary + +from common.id import ( + AnimationId, AnimationFrameId, + CapArgId, CapId, + HIDId, + NoneId, + PixelId, PixelLayerId, + ScanCodeId +) +from common.modifier import AnimationModifierList +from common.schedule import AnalogScheduleParam, ScheduleParam, Time + +from funcparserlib.lexer import Token +from funcparserlib.parser import (some, a, many, oneplus, skip, maybe) + + + + +### Decorators ### + +## Print Decorator Variables +ERROR = '\033[5;1;31mERROR\033[0m:' +WARNING = '\033[5;1;33mWARNING\033[0m:' + + + +### Classes ### + +## Parsing Functions + +class Make: + ''' + Collection of parse string interpreters + ''' + + def scanCode( token ): + ''' + Converts a raw scan code string into an ScanCodeId /w integer + + S0x10 -> 16 + ''' + if isinstance( token, int ): + return ScanCodeId( token ) + else: + return ScanCodeId( int( token[1:], 0 ) ) + + def hidCode( type, token ): + ''' + Convert a given raw hid token string to an integer /w a type + + U"Enter" -> USB, Enter(0x28) + ''' + # If already converted to a HIDId, just return + if isinstance( token, HIDId ): + return token + + # If first character is a U or I, strip + if token[0] == "U" or token[0] == "I": + token = token[1:] + # CONS specifier + elif 'CONS' in token: + token = token[4:] + # SYS specifier + elif 'SYS' in token: + token = token[3:] + + # If using string representation of USB Code, do lookup, case-insensitive + if '"' in token: + try: + hidCode = kll_hid_lookup_dictionary[ type ][ token[1:-1].upper() ][1] + except LookupError as err: + print ( "{0} {1} is an invalid USB HID Code Lookup...".format( ERROR, err ) ) + raise + else: + # Already tokenized + if ( + type == 'USBCode' and token[0] == 'USB' + or + type == 'SysCode' and token[0] == 'SYS' + or + type == 'ConsCode' and token[0] == 'CONS' + or + type == 'IndCode' and token[0] == 'IND' + ): + hidCode = token[1] + # Convert + else: + hidCode = int( token, 0 ) + + return HIDId( type, hidCode ) + + + def usbCode( token ): + ''' + Convert a given raw USB Keyboard hid token string to an integer /w a type + + U"Enter" -> USB, Enter(0x28) + ''' + return Make.hidCode( 'USBCode', token ) + + def consCode( token ): + ''' + Convert a given raw Consumer Control hid token string to an integer /w a type + ''' + return Make.hidCode( 'ConsCode', token ) + + def sysCode( token ): + ''' + Convert a given raw System Control hid token string to an integer /w a type + ''' + return Make.hidCode( 'SysCode', token ) + + def indCode( token ): + ''' + Convert a given raw Indicator hid token string to an integer /w a type + ''' + return Make.hidCode( 'IndCode', token ) + + def animation( name ): + ''' + Converts a raw animation value into an AnimationId /w name + + A"myname" -> myname + ''' + if name[0] == "A": + return AnimationId( name[2:-1] ) + else: + return AnimationId( name ) + + def animationTrigger( animation, frame_indices ): + ''' + Generate either an AnimationId or an AnimationFrameId + + frame_indices indicate that this is an AnimationFrameId + ''' + trigger_list = [] + # AnimationFrameId + if len( frame_indices ) > 0: + for index in frame_indices: + trigger_list.append( [ [ AnimationFrameId( animation, index ) ] ] ) + # AnimationId + else: + trigger_list.append( [ [ AnimationId( animation ) ] ] ) + + return trigger_list + + def animationCapability( animation, modifiers ): + ''' + Apply modifiers to AnimationId + ''' + if modifiers is not None: + animation.setModifiers( modifiers ) + return [ animation ] + + def animationModlist( modifiers ): + ''' + Build an AnimationModifierList + + Only used for animation data association + ''' + modlist = AnimationModifierList() + modlist.setModifiers( modifiers ) + return modlist + + def pixelCapability( pixels, modifiers ): + ''' + Apply modifiers to list of pixels/pixellists + + Results in a combination of pixel capabilities + ''' + pixelcap_list = [] + for pixel in pixels: + pixel.setModifiers( modifiers ) + pixelcap_list.append( pixel ) + return pixelcap_list + + def pixel( token ): + ''' + Converts a raw pixel value into a PixelId /w integer + + P0x3 -> 3 + ''' + if isinstance( token, int ): + return PixelId( token ) + else: + return PixelId( int( token[1:], 0 ) ) + + def pixel_list( pixel_list ): + ''' + Converts a list a numbers into a list of PixelIds + ''' + pixels = [] + for pixel in pixel_list: + pixels.append( PixelId( pixel ) ) + return pixels + + def pixelLayer( token ): + ''' + Converts a raw pixel layer value into a PixelLayerId /w integer + + PL0x3 -> 3 + ''' + if isinstance( token, int ): + return PixelLayerId( token ) + else: + return PixelLayerId( int( token[2:], 0 ) ) + + def pixelLayer_list( layer_list ): + ''' + Converts a list a numbers into a list of PixelLayerIds + ''' + layers = [] + for layer in layer_list: + layers.append( PixelLayerId( layer ) ) + return layers + + def pixelchan( pixel_list, chans ): + ''' + Apply channels to PixelId + + Only one pixel at a time can be mapped, hence pixel_list[0] + ''' + pixel = pixel_list[0] + pixel.setChannels( chans ) + return pixel + + def pixelmod( pixels, modifiers ): + ''' + Apply modifiers to list of pixels/pixellists + + Results in a combination of pixel capabilities + ''' + pixelcap_list = [] + for pixel in pixels: + pixel.setModifiers( modifiers ) + pixelcap_list.append( pixel ) + return pixelcap_list + + def position( token ): + ''' + Physical position split + + x:20 -> (x, 20) + ''' + return token.split(':') + + def usbCode_number( token ): + ''' + USB Keyboard HID Code lookup + ''' + return HIDId( 'USBCode', token ) + + def consCode_number( token ): + ''' + Consumer Control HID Code lookup + ''' + return HIDId( 'ConsCode', token ) + + def sysCode_number( token ): + ''' + System Control HID Code lookup + ''' + return HIDId( 'SysCode', token ) + + def indCode_number( token ): + ''' + Indicator HID Code lookup + ''' + return HIDId( 'IndCode', token ) + + def none( token ): + ''' + Replace key-word with NoneId specifier (which indicates a noneOut capability) + ''' + return [[[NoneId()]]] + + def seqString( token ): + ''' + Converts sequence string to a sequence of combinations + + 'Ab' -> U"Shift" + U"A", U"B" + ''' + # TODO - Add locale support + + # Shifted Characters, and amount to move by to get non-shifted version + # US ANSI + shiftCharacters = ( + ( "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0x20 ), + ( "+", 0x12 ), + ( "&(", 0x11 ), + ( "!#$%", 0x10 ), + ( "*", 0x0E ), + ( ")", 0x07 ), + ( '"', 0x05 ), + ( ":", 0x01 ), + ( "@", -0x0E ), + ( "<>?", -0x10 ), + ( "~", -0x1E ), + ( "{}|", -0x20 ), + ( "^", -0x28 ), + ( "_", -0x32 ), + ) + + listOfLists = [] + shiftKey = kll_hid_lookup_dictionary['USBCode']["SHIFT"] + + # Creates a list of USB codes from the string: sequence (list) of combos (lists) + for char in token[1:-1]: + processedChar = char + + # Whether or not to create a combo for this sequence with a shift + shiftCombo = False + + # Depending on the ASCII character, convert to single character or Shift + character + for pair in shiftCharacters: + if char in pair[0]: + shiftCombo = True + processedChar = chr( ord( char ) + pair[1] ) + break + + # Do KLL HID Lookup on non-shifted character + # NOTE: Case-insensitive, which is why the shift must be pre-computed + usb_code = kll_hid_lookup_dictionary['USBCode'][ processedChar.upper() ] + + # Create Combo for this character, add shift key if shifted + charCombo = [] + if shiftCombo: + charCombo = [ [ HIDId( 'USBCode', shiftKey[1] ) ] ] + charCombo.append( [ HIDId( 'USBCode', usb_code[1] ) ] ) + + # Add to list of lists + listOfLists.append( charCombo ) + + return listOfLists + + def string( token ): + ''' + Converts a raw string to a Python string + + "this string" -> this string + ''' + return token[1:-1] + + def unseqString( token ): + ''' + Converts a raw sequence string to a Python string + + 'this string' -> this string + ''' + return token[1:-1] + + def number( token ): + ''' + Convert string number to Python integer + ''' + return int( token, 0 ) + + def timing( token ): + ''' + Convert raw timing parameter to integer time and determine units + + 1ms -> 1, ms + ''' + # Find ms, us, or s + if 'ms' in token: + unit = 'ms' + num = token.split('m')[0] + elif 'us' in token: + unit = 'us' + num = token.split('u')[0] + elif 'ns' in token: + unit = 'ns' + num = token.split('n')[0] + elif 's' in token: + unit = 's' + num = token.split('s')[0] + else: + print ( "{0} cannot find timing unit in token '{1}'".format( ERROR, token ) ) + + return Time( float( num ), unit ) + + def specifierTiming( timing ): + ''' + When only timing is given, infer state at a later stage from the context of the mapping + ''' + return ScheduleParam( None, timing ) + + def specifierState( state, timing=None ): + ''' + Generate a Schedule Parameter + Automatically mutates itself into the correct object type + ''' + return ScheduleParam( state, timing ) + + def specifierAnalog( value ): + ''' + Generate an Analog Schedule Parameter + ''' + return AnalogScheduleParam( value ) + + def specifierUnroll( identifier, schedule_params ): + ''' + Unroll specifiers into the trigger/result identifier + + First, combine all Schedule Parameters into a Schedul + Then attach Schedule to the identifier + + If the identifier is a list, then iterate through them + and apply the schedule to each + ''' + # Check if this is a list of identifiers + if isinstance( identifier, list ): + for ident in identifier: + ident.setSchedule( schedule_params ) + return identifier + else: + identifier.setSchedule( schedule_params ) + + return [ identifier ] + + + # Range can go from high to low or low to high + def scanCode_range( rangeVals ): + ''' + Scan Code range expansion + + S[0x10-0x12] -> S0x10, S0x11, S0x12 + ''' + start = rangeVals[0] + end = rangeVals[1] + + # Swap start, end if start is greater than end + if start > end: + start, end = end, start + + # Iterate from start to end, and generate the range + values = list( range( start, end + 1 ) ) + + # Generate ScanCodeIds + return [ ScanCodeId( v ) for v in values ] + + # Range can go from high to low or low to high + # Warn on 0-9 for USBCodes (as this does not do what one would expect) TODO + # Lookup USB HID tags and convert to a number + def hidCode_range( type, rangeVals ): + ''' + HID Code range expansion + + U["A"-"C"] -> U"A", U"B", U"C" + ''' + + # Check if already integers + if isinstance( rangeVals[0], int ): + start = rangeVals[0] + else: + start = Make.hidCode( type, rangeVals[0] ).uid + + if isinstance( rangeVals[1], int ): + end = rangeVals[1] + else: + end = Make.hidCode( type, rangeVals[1] ).uid + + # Swap start, end if start is greater than end + if start > end: + start, end = end, start + + # Iterate from start to end, and generate the range + listRange = list( range( start, end + 1 ) ) + + # Convert each item in the list to a tuple + for item in range( len( listRange ) ): + listRange[ item ] = HIDId( type, listRange[ item ] ) + return listRange + + def usbCode_range( rangeVals ): + ''' + USB Keyboard HID Code range expansion + ''' + return Make.hidCode_range( 'USBCode', rangeVals ) + + def sysCode_range( rangeVals ): + ''' + System Control HID Code range expansion + ''' + return Make.hidCode_range( 'SysCode', rangeVals ) + + def consCode_range( rangeVals ): + ''' + Consumer Control HID Code range expansion + ''' + return Make.hidCode_range( 'ConsCode', rangeVals ) + + def indCode_range( rangeVals ): + ''' + Indicator HID Code range expansion + ''' + return Make.hidCode_range( 'IndCode', rangeVals ) + + def range( start, end ): + ''' + Converts a start and end points of a range to a list of numbers + + Can go low to high or high to low + ''' + # High to low + if end < start: + return list( range( end, start + 1 ) ) + + # Low to high + return list( range( start, end + 1 ) ) + + def capArg( argument, width=None ): + ''' + Converts a capability argument:width to a CapArgId + + If no width is specified, it is ignored + ''' + return CapArgId( argument, width ) + + def capUsage( name, arguments ): + ''' + Converts a capability tuple, argument list to a CapId Usage + ''' + return CapId( name, 'Usage', arguments ) + + + +### Rules ### + +## Base Rules + +const = lambda x: lambda _: x +unarg = lambda f: lambda x: f(*x) +flatten = lambda list: sum( list, [] ) + +tokenValue = lambda x: x.value +tokenType = lambda t: some( lambda x: x.type == t ) >> tokenValue +operator = lambda s: a( Token( 'Operator', s ) ) >> tokenValue +parenthesis = lambda s: a( Token( 'Parenthesis', s ) ) >> tokenValue +bracket = lambda s: a( Token( 'Bracket', s ) ) >> tokenValue +eol = a( Token( 'EndOfLine', ';' ) ) + +def maybeFlatten( items ): + ''' + Iterate through top-level lists + Flatten, only if the element is also a list + + [[1,2],3,[[4,5]]] -> [1,2,3,[4,5]] + ''' + new_list = [] + for elem in items: + # Flatten only if a list + if isinstance( elem, list ): + new_list.extend( elem ) + else: + new_list.append( elem ) + return new_list + +def listElem( item ): + ''' + Convert to a list element + ''' + return [ item ] + +def listToTuple( items ): + ''' + Convert list to a tuple + ''' + return tuple( items ) + +def oneLayerFlatten( items ): + ''' + Flatten only the top layer (list of lists of ...) + ''' + mainList = [] + for sublist in items: + for item in sublist: + mainList.append( item ) + + return mainList + +def optionExpansion( sequences ): + ''' + Expand ranges of values in the 3rd dimension of the list, to a list of 2nd lists + + i.e. [ sequence, [ combo, [ range ] ] ] --> [ [ sequence, [ combo ] ],