Example #1
0
    def merge_lazy_operators(self, debug):
        '''
        Lazy Set :: is not applied as a Set : until after the merge_in_log has been pruned

        Intended to be called during reduction.
        '''
        # Build dictionary of single ScanCodes first
        result_code_lookup = {}
        for key, expr in self.data.items():
            if expr[0].elems(
            )[0] == 1 and expr[0].triggers[0][0][0].type == 'ScanCode':
                result_code_lookup.setdefault(expr[0].result_str(),
                                              []).append(key)

        # Build list of lazy keys from log
        lazy_keys = {}
        for key, expr, enabled in reversed(self.merge_in_log):
            if key[0:2] == '::' or key[0:3] == 'i::':
                if key not in lazy_keys.keys():
                    # Debug info
                    if debug:
                        print("\033[1mLazy\033[0m", key, expr)

                    # Determine the target key from the expression
                    target_key = expr.trigger_str()
                    lazy_keys[target_key] = expr

                    # Check if we need to do a lazy replacement
                    if target_key in result_code_lookup.keys():
                        expr_keys = result_code_lookup[target_key]
                        for target_expr_key in expr_keys:
                            # Calculate new key
                            new_expr = self.data[target_expr_key][0]
                            new_key = "{0}{1}".format(
                                new_expr.operator,
                                new_expr.unique_keys()[0][0])

                            # Determine action based on the new_expr.operator
                            orig_expr = self.data[new_key][0]

                            if debug:
                                print(
                                    "\t\033[1;32mREPLACE\033[0m {0} -> {1}\n\t{2} => {3}"
                                    .format(target_expr_key, new_key, expr,
                                            new_expr))

                            # Do replacement
                            self.data[new_key] = [
                                expression.MapExpression(
                                    orig_expr.triggers, orig_expr.operator,
                                    expr.results)
                            ]
                            self.data[new_key][
                                0].connect_id = orig_expr.connect_id

                            # Unset basemap on expression
                            self.data[new_key][0].base_map = False
Example #2
0
    def reduction(self, debug=False):
        '''
		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
		'''
        result_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':
                result_code_lookup[expr[0].result_str()] = expr

        # Using this dictionary, replace all the trigger USB codes
        # Iterate over a copy so we can modify the dictionary in place
        for key, expr in self.data.copy().items():
            for sub_expr in expr:
                # 1) Single USB Codes trigger results will replace the original ScanCode result
                if sub_expr.elems(
                )[0] == 1 and sub_expr.triggers[0][0][0].type != 'ScanCode':
                    # Debug info
                    if debug:
                        print("\033[1mSingle\033[0m", key, expr)

                    # Lookup trigger to see if it exists
                    trigger_str = sub_expr.trigger_str()
                    if trigger_str in result_code_lookup.keys():
                        # Calculate new key
                        new_expr = result_code_lookup[trigger_str][0]
                        new_key = "{0}{1}".format(new_expr.operator,
                                                  new_expr.unique_keys()[0][0])

                        # Determine action based on the new_expr.operator
                        orig_expr = self.data[new_key][0]
                        # Replace expression
                        if sub_expr.operator in ['::', ':']:
                            if debug:
                                print(
                                    "\t\033[1;32mREPLACE\033[0m {0} -> {1}\n\t{2} => {3}"
                                    .format(key, new_key, sub_expr, new_expr))

                            # Do replacement
                            self.data[new_key] = [
                                expression.MapExpression(
                                    orig_expr.triggers, orig_expr.operator,
                                    sub_expr.results)
                            ]

                            # Unset basemap on expression
                            self.data[new_key][0].base_map = False

                        # Add expression
                        elif sub_expr.operator in [':+']:
                            if debug:
                                print(
                                    "\t\033[1;42mADD\033[0m {0} -> {1}\n\t{2} => {3}"
                                    .format(key, new_key, sub_expr, new_expr))

                            # Add expression
                            self.data[new_key].append(
                                expression.MapExpression(
                                    orig_expr.triggers, orig_expr.operator,
                                    sub_expr.results))

                            # Unset basemap on sub results
                            for sub_expr in self.data[new_key]:
                                sub_expr.base_map = False

                        # Remove expression
                        elif sub_expr.operator in [':-']:
                            if debug:
                                print(
                                    "\t\033[1;41mREMOVE\033[0m {0} -> {1}\n\t{2} => {3}"
                                    .format(key, new_key, sub_expr, new_expr))

                        # Remove old key
                        if key in self.data.keys():
                            del self.data[key]

                    # Otherwise drop HID expression
                    else:
                        if debug:
                            print("\t\033[1;34mDROP\033[0m")
                        del self.data[key]

                # 2) Complex triggers are processed to replace out any USB Codes with Scan Codes
                elif sub_expr.elems()[0] > 1:
                    # Debug info
                    if debug:
                        print("\033[1;4mMulti\033[0m ", key, expr)

                    # Lookup each trigger element and replace
                    # If any trigger element doesn't exist, drop expression
                    # Dive through sequence->combo->identifier (sequence of combos of ids)
                    replace = False
                    drop = False
                    for seq_in, sequence in enumerate(sub_expr.triggers):
                        for com_in, combo in enumerate(sequence):
                            for ident_in, identifier in enumerate(combo):
                                ident_str = "({0})".format(identifier)

                                # Replace identifier
                                if ident_str in result_code_lookup.keys():
                                    match_expr = result_code_lookup[ident_str]
                                    sub_expr.triggers[seq_in][com_in][
                                        ident_in] = match_expr[0].triggers[0][
                                            0][0]
                                    replace = True

                                # Ignore ScanCodes
                                elif identifier.type == 'ScanCode':
                                    pass

                                # Drop everything else
                                else:
                                    drop = True

                    # Trigger Identifier was replaced
                    if replace:
                        if debug:
                            print("\t\033[1;32mREPLACE\033[0m", expr)

                    # Trigger Identifier failed (may still occur if there was a replacement)
                    if drop:
                        if debug:
                            print("\t\033[1;34mDROP\033[0m")
                        del self.data[key]

        # Show results of reduction
        if debug:
            print(self)
Example #3
0
    def reduction(self, debug=False):
        '''
        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
        '''
        result_code_lookup = {}

        # Prune merge_in_log
        merge_in_pruned = self.merge_in_log_prune(debug)

        # 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':
                result_code_lookup[expr[0].result_str()] = expr

        # Skip if dict is empty
        if len(self.data.keys()) == 0:
            return

        # Instead of using the .data dictionary, use the merge_in_log which maintains the expression application order
        # Using this list, replace all the trigger USB codes
        for key, log_expr, active in self.merge_in_log:
            # Skip if not active
            if not active:
                continue

            # Lookup currently merged expression
            if key not in self.data.keys():
                continue
            expr = self.data[key]

            for sub_expr in expr:
                # 1) Single USB Codes trigger results will replace the original ScanCode result
                if sub_expr.elems(
                )[0] == 1 and sub_expr.triggers[0][0][0].type in [
                        'USBCode', 'SysCode', 'ConsCode'
                ]:
                    # Debug info
                    if debug:
                        print("\033[1mSingle\033[0m", key, expr)

                    # Lookup trigger to see if it exists
                    trigger_str = sub_expr.trigger_str()
                    if trigger_str in result_code_lookup.keys():
                        # Calculate new key
                        new_expr = result_code_lookup[trigger_str][0]
                        new_key = "{0}{1}".format(new_expr.operator,
                                                  new_expr.unique_keys()[0][0])

                        # Determine action based on the new_expr.operator
                        orig_expr = self.data[new_key][0]

                        # Replace expression
                        if sub_expr.operator in [':']:
                            if debug:
                                print(
                                    "\t\033[1;32mREPLACE\033[0m {0} -> {1}\n\t{2} => {3}"
                                    .format(key, new_key, sub_expr, new_expr))

                            # Do replacement
                            self.data[new_key] = [
                                expression.MapExpression(
                                    orig_expr.triggers, orig_expr.operator,
                                    sub_expr.results)
                            ]

                            # Transfer connect_id
                            self.data[new_key][
                                0].connect_id = orig_expr.connect_id

                            # Unset basemap on expression
                            self.data[new_key][0].base_map = False

                        # Add expression
                        elif sub_expr.operator in [':+']:
                            if debug:
                                print(
                                    "\t\033[1;42mADD\033[0m {0} -> {1}\n\t{2} => {3}"
                                    .format(key, new_key, sub_expr, new_expr))

                            # Add expression
                            self.data[new_key].append(
                                expression.MapExpression(
                                    orig_expr.triggers, orig_expr.operator,
                                    sub_expr.results))

                            # Unset basemap on sub results
                            for sub_expr in self.data[new_key]:
                                sub_expr.base_map = False

                        # Remove expression
                        elif sub_expr.operator in [':-']:
                            if debug:
                                print(
                                    "\t\033[1;41mREMOVE\033[0m {0} -> {1}\n\t{2} => {3}"
                                    .format(key, new_key, sub_expr, new_expr))

                        # Remove old key
                        if key in self.data.keys():
                            del self.data[key]

                    # Otherwise drop HID expression
                    else:
                        if debug:
                            print("\t\033[1;34mDROP\033[0m")
                        if key in self.data.keys():
                            del self.data[key]

                # 2) Complex triggers are processed to replace out any USB Codes with Scan Codes
                elif sub_expr.elems()[0] > 1:
                    # Debug info
                    if debug:
                        print("\033[1;4mMulti\033[0m ", key, expr)

                    # Lookup each trigger element and replace
                    # If any trigger element doesn't exist, drop expression
                    # Dive through sequence->combo->identifier (sequence of combos of ids)
                    replace = False
                    drop = False
                    for seq_in, sequence in enumerate(sub_expr.triggers):
                        for com_in, combo in enumerate(sequence):
                            for ident_in, identifier in enumerate(combo):
                                ident_str = "({0})".format(identifier)

                                # Replace identifier
                                if ident_str in result_code_lookup.keys():
                                    match_expr = result_code_lookup[ident_str]
                                    sub_expr.triggers[seq_in][com_in][
                                        ident_in] = match_expr[0].triggers[0][
                                            0][0]
                                    replace = True

                                # Ignore non-USB triggers
                                elif identifier.type in [
                                        'IndCode', 'GenericTrigger', 'Layer',
                                        'LayerLock', 'LayerShift',
                                        'LayerLatch', 'ScanCode'
                                ]:
                                    pass

                                # Drop everything else
                                else:
                                    drop = True

                    # Trigger Identifier was replaced
                    if replace:
                        if debug:
                            print("\t\033[1;32mREPLACE\033[0m", expr)

                    # Trigger Identifier failed (may still occur if there was a replacement)
                    if drop:
                        if debug:
                            print("\t\033[1;34mDROP\033[0m")
                        del self.data[key]

        # Finally we can merge in the Lazy :: Set operators
        self.merge_lazy_operators(debug)

        # Show results of reduction
        if debug:
            print(self)