예제 #1
0
    def _populate_ui(self):
        self.split_slider.setValue(self.action_data.center_point * 1e5)
        self.split_readout.setValue(self.action_data.center_point)
        try:
            if self.action_data.device_low_vjoy_id is None or \
                    self.action_data.device_low_axis is None:
                self.vjoy_selector_1.set_selection(InputType.JoystickAxis, -1,
                                                   -1)
            else:
                self.vjoy_selector_1.set_selection(
                    InputType.JoystickAxis,
                    self.action_data.device_low_vjoy_id,
                    self.action_data.device_low_axis)
            if self.action_data.device_high_vjoy_id is None or \
                    self.action_data.device_high_axis is None:
                self.vjoy_selector_2.set_selection(InputType.JoystickAxis, -1,
                                                   -1)
            else:
                self.vjoy_selector_2.set_selection(
                    InputType.JoystickAxis,
                    self.action_data.device_high_vjoy_id,
                    self.action_data.device_high_axis)

            self.save_vjoy_selection(1, self.vjoy_selector_1.get_selection())
            self.save_vjoy_selection(2, self.vjoy_selector_2.get_selection())
        except gremlin.error.GremlinError as e:
            # FIXME: This error here should only have been needed due to the
            #        vJoy selector attempting to acquire a vJoy device, this
            #        should no longer occur, check if this here is still needed
            util.display_error(
                "A needed vJoy device is not accessible: {}\n\n".format(e) +
                "Default values have been set for the input, but they are "
                "not what has been specified.")
            logging.getLogger("system").error(str(e))
예제 #2
0
    def _populate_ui(self):
        """Populates the UI components."""
        # Get the appropriate vjoy device identifier
        vjoy_dev_id = 0
        if self.action_data.vjoy_device_id not in [0, None]:
            vjoy_dev_id = self.action_data.vjoy_device_id

        # Get the input type which can change depending on the container used
        input_type = self.action_data.input_type
        if self.action_data.parent.tag == "hat_buttons":
            input_type = InputType.JoystickButton

        # If no valid input item is selected get the next unused one
        if self.action_data.vjoy_input_id in [0, None]:
            free_inputs = self._get_profile_root().list_unused_vjoy_inputs()

            input_name = self.type_to_name_map[input_type].lower()
            input_type = self.name_to_type_map[input_name.capitalize()]
            if vjoy_dev_id == 0:
                vjoy_dev_id = sorted(free_inputs.keys())[0]
            input_list = free_inputs[vjoy_dev_id][input_name]
            # If we have an unused item use it, otherwise use the first one
            if len(input_list) > 0:
                vjoy_input_id = input_list[0]
            else:
                vjoy_input_id = 1
        # If a valid input item is present use it
        else:
            vjoy_input_id = self.action_data.vjoy_input_id

        try:
            self.vjoy_selector.set_selection(input_type, vjoy_dev_id,
                                             vjoy_input_id)

            if self.action_data.input_type == InputType.JoystickAxis:
                if self.action_data.axis_mode == "absolute":
                    self.absolute_checkbox.setChecked(True)
                else:
                    self.relative_checkbox.setChecked(True)
                self.relative_scaling.setValue(self.action_data.axis_scaling)

                self.absolute_checkbox.clicked.connect(self.save_changes)
                self.relative_checkbox.clicked.connect(self.save_changes)
                self.relative_scaling.valueChanged.connect(self.save_changes)

            # Save changes so the UI updates properly
            self.save_changes()
        except gremlin.error.GremlinError as e:
            util.display_error(
                "A needed vJoy device is not accessible: {}\n\n".format(e) +
                "Default values have been set for the input, but they are "
                "not what has been specified.")
            logging.getLogger("system").error(str(e))
예제 #3
0
 def _populate_ui(self):
     self.split_slider.setValue(self.action_data.center_point * 1e5)
     self.split_readout.setValue(self.action_data.center_point)
     try:
         if self.action_data.axis1 is None:
             self.vjoy_selector_1.set_selection(InputType.JoystickAxis, -1,
                                                -1)
         else:
             self.vjoy_selector_1.set_selection(InputType.JoystickAxis,
                                                self.action_data.axis1[0],
                                                self.action_data.axis1[1])
         if self.action_data.axis2 is None:
             self.vjoy_selector_2.set_selection(InputType.JoystickAxis, -1,
                                                -1)
         else:
             self.vjoy_selector_2.set_selection(InputType.JoystickAxis,
                                                self.action_data.axis2[0],
                                                self.action_data.axis2[1])
     except gremlin.error.GremlinError as e:
         util.display_error(
             "A needed vJoy device is not accessible: {}\n\n".format(e) +
             "Default values have been set for the input, but they are "
             "not what has been specified.")
         logging.getLogger("system").error(str(e))
예제 #4
0
    def start(self, inheritance_tree, settings, start_mode, profile):
        """Starts listening to events and loads all existing callbacks.

        :param inheritance_tree tree encoding inheritance between the
            different modes
        :param settings profile settings to apply at launch
        :param start_mode the mode in which to start Gremlin
        :param profile the profile to use when generating all the callbacks
        """
        # Reset states to their default values
        self._inheritance_tree = inheritance_tree
        self._reset_state()

        # Check if we want to override the star mode as determined by the
        # heuristic
        if settings.startup_mode is not None:
            if settings.startup_mode in gremlin.profile.mode_list(profile):
                start_mode = settings.startup_mode

        # Load the generated code
        try:
            # Load generated python code
            gremlin_code = util.load_module("gremlin_code")

            # Create callbacks fom the user code
            callback_count = 0
            for dev_id, modes in input_devices.callback_registry.registry.items(
            ):
                for mode, callbacks in modes.items():
                    for event, callback_list in callbacks.items():
                        for callback in callback_list.values():
                            self.event_handler.add_callback(
                                dev_id, mode, event, callback[0], callback[1])
                            callback_count += 1

            # Create input callbacks based on the profile's content
            for device in profile.devices.values():
                hid = device.hardware_id
                wid = device.windows_id
                dev_id = util.get_device_id(hid, wid)
                for mode in device.modes.values():
                    for input_items in mode.config.values():
                        for input_item in input_items.values():
                            # Only add callbacks for input items that actually
                            # contain actions
                            if len(input_item.containers) == 0:
                                continue

                            event = event_handler.Event(
                                event_type=input_item.input_type,
                                hardware_id=hid,
                                windows_id=wid,
                                identifier=input_item.input_id)

                            self.event_handler.add_callback(
                                dev_id, mode.name, event,
                                InputItemCallback(input_item),
                                input_item.always_execute)

            # Create merge axis callbacks
            for entry in profile.merge_axes:
                merge_axis = MergeAxis(entry["vjoy"]["device_id"],
                                       entry["vjoy"]["axis_id"])
                self._merge_axes.append(merge_axis)

                # Lower axis callback
                event = event_handler.Event(
                    event_type=gremlin.common.InputType.JoystickAxis,
                    hardware_id=entry["lower"]["hardware_id"],
                    windows_id=entry["lower"]["windows_id"],
                    identifier=entry["lower"]["axis_id"])
                self.event_handler.add_callback(
                    util.get_device_id(entry["lower"]["hardware_id"],
                                       entry["lower"]["windows_id"]),
                    entry["mode"], event, merge_axis.update_axis1, False)

                # Upper axis callback
                event = event_handler.Event(
                    event_type=gremlin.common.InputType.JoystickAxis,
                    hardware_id=entry["upper"]["hardware_id"],
                    windows_id=entry["upper"]["windows_id"],
                    identifier=entry["upper"]["axis_id"])
                self.event_handler.add_callback(
                    util.get_device_id(entry["upper"]["hardware_id"],
                                       entry["upper"]["windows_id"]),
                    entry["mode"], event, merge_axis.update_axis2, False)

            # Create vJoy response curve setups
            self._vjoy_curves.profile_data = profile.vjoy_devices
            self.event_handler.mode_changed.connect(
                self._vjoy_curves.mode_changed)

            # Use inheritance to build input action lookup table
            self.event_handler.build_event_lookup(inheritance_tree)

            # Set vJoy axis default values
            for vid, data in settings.vjoy_initial_values.items():
                vjoy_proxy = joystick_handling.VJoyProxy()[vid]
                for aid, value in data.items():
                    vjoy_proxy.axis(aid).set_absolute_value(value)

            # Connect signals
            evt_listener = event_handler.EventListener()
            kb = input_devices.Keyboard()
            evt_listener.keyboard_event.connect(
                self.event_handler.process_event)
            evt_listener.joystick_event.connect(
                self.event_handler.process_event)
            evt_listener.keyboard_event.connect(kb.keyboard_event)

            input_devices.periodic_registry.start()
            macro.MacroManager().start()

            self.event_handler.change_mode(start_mode)
            self.event_handler.resume()
            self._running = True
        except ImportError as e:
            util.display_error(
                "Unable to launch due to missing custom modules: {}".format(
                    str(e)))
예제 #5
0
    def start(self, inheritance_tree, settings, start_mode, profile):
        """Starts listening to events and loads all existing callbacks.

        :param inheritance_tree tree encoding inheritance between the
            different modes
        :param settings profile settings to apply at launch
        :param start_mode the mode in which to start Gremlin
        :param profile the profile to use when generating all the callbacks
        """
        # Reset states to their default values
        self._inheritance_tree = inheritance_tree
        self._reset_state()

        # Check if we want to override the start mode as determined by the
        # heuristic
        if settings.startup_mode is not None:
            if settings.startup_mode in gremlin.profile.mode_list(profile):
                start_mode = settings.startup_mode

        # Set default macro action delay
        gremlin.macro.MacroManager().default_delay = settings.default_delay

        # Retrieve list of current paths searched by Python
        system_paths = [os.path.normcase(os.path.abspath(p)) for p in sys.path]

        # Load the generated code
        try:
            # Populate custom module variable registry
            var_reg = user_plugin.variable_registry
            for plugin in profile.plugins:
                # Perform system path mangling for import statements
                path, _ = os.path.split(
                    os.path.normcase(os.path.abspath(plugin.file_name))
                )
                if path not in system_paths:
                    system_paths.append(path)

                # Load module specification so we can later create multiple
                # instances if desired
                spec = importlib.util.spec_from_file_location(
                    "".join(random.choices(string.ascii_lowercase, k=16)),
                    plugin.file_name
                )

                # Process each instance in turn
                for instance in plugin.instances:
                    # Skip all instances that are not fully configured
                    if not instance.is_configured():
                        continue

                    # Store variable values in the registry
                    for var in instance.variables.values():
                        var_reg.set(
                            plugin.file_name,
                            instance.name,
                            var.name,
                            var.value
                        )

                    # Load the modules
                    tmp = importlib.util.module_from_spec(spec)
                    tmp.__gremlin_identifier = (plugin.file_name, instance.name)
                    spec.loader.exec_module(tmp)

            # Update system path list searched by Python
            sys.path = system_paths

            # Create callbacks fom the user code
            callback_count = 0
            for dev_id, modes in input_devices.callback_registry.registry.items():
                for mode, events in modes.items():
                    for event, callback_list in events.items():
                        for callback in callback_list.values():
                            self.event_handler.add_callback(
                                dev_id,
                                mode,
                                event,
                                callback[0],
                                callback[1]
                            )
                            callback_count += 1

            # Add a fake keyboard action which does nothing to the callbacks
            # in every mode in order to have empty modes be "present"
            for mode_name in gremlin.profile.mode_list(profile):
                self.event_handler.add_callback(
                    0,
                    mode_name,
                    None,
                    lambda x: x,
                    False
                )

            # Create input callbacks based on the profile's content
            for device in profile.devices.values():
                for mode in device.modes.values():
                    for input_items in mode.config.values():
                        for input_item in input_items.values():
                            # Only add callbacks for input items that actually
                            # contain actions
                            if len(input_item.containers) == 0:
                                continue

                            event = event_handler.Event(
                                event_type=input_item.input_type,
                                device_guid=device.device_guid,
                                identifier=input_item.input_id
                            )

                            # Create possibly several callbacks depending
                            # on the input item's content
                            callbacks = []
                            for container in input_item.containers:
                                if not container.is_valid():
                                    logging.getLogger("system").warning(
                                        "Incomplete container ignored"
                                    )
                                    continue
                                callbacks.extend(container.generate_callbacks())

                            for cb_data in callbacks:
                                if cb_data.event is None:
                                    self.event_handler.add_callback(
                                        device.device_guid,
                                        mode.name,
                                        event,
                                        cb_data.callback,
                                        input_item.always_execute
                                    )
                                else:
                                    self.event_handler.add_callback(
                                        dill.GUID_Virtual,
                                        mode.name,
                                        cb_data.event,
                                        cb_data.callback,
                                        input_item.always_execute
                                    )

            # Create merge axis callbacks
            for entry in profile.merge_axes:
                merge_axis = MergeAxis(
                    entry["vjoy"]["vjoy_id"],
                    entry["vjoy"]["axis_id"],
                    entry["operation"]
                )
                self._merge_axes.append(merge_axis)

                # Lower axis callback
                event = event_handler.Event(
                    event_type=gremlin.common.InputType.JoystickAxis,
                    device_guid=entry["lower"]["device_guid"],
                    identifier=entry["lower"]["axis_id"]
                )
                self.event_handler.add_callback(
                    event.device_guid,
                    entry["mode"],
                    event,
                    merge_axis.update_axis1,
                    False
                )

                # Upper axis callback
                event = event_handler.Event(
                    event_type=gremlin.common.InputType.JoystickAxis,
                    device_guid=entry["upper"]["device_guid"],
                    identifier=entry["upper"]["axis_id"]
                )
                self.event_handler.add_callback(
                    event.device_guid,
                    entry["mode"],
                    event,
                    merge_axis.update_axis2,
                    False
                )

            # Create vJoy response curve setups
            self._vjoy_curves.profile_data = profile.vjoy_devices
            self.event_handler.mode_changed.connect(
                self._vjoy_curves.mode_changed
            )

            # Use inheritance to build input action lookup table
            self.event_handler.build_event_lookup(inheritance_tree)

            # Set vJoy axis default values
            for vid, data in settings.vjoy_initial_values.items():
                vjoy_proxy = joystick_handling.VJoyProxy()[vid]
                for aid, value in data.items():
                    vjoy_proxy.axis(linear_index=aid).set_absolute_value(value)

            # Connect signals
            evt_listener = event_handler.EventListener()
            kb = input_devices.Keyboard()
            evt_listener.keyboard_event.connect(
                self.event_handler.process_event
            )
            evt_listener.joystick_event.connect(
                self.event_handler.process_event
            )
            evt_listener.virtual_event.connect(
                self.event_handler.process_event
            )
            evt_listener.keyboard_event.connect(kb.keyboard_event)
            evt_listener.gremlin_active = True

            input_devices.periodic_registry.start()
            macro.MacroManager().start()

            self.event_handler.change_mode(start_mode)
            self.event_handler.resume()
            self._running = True

            sendinput.MouseController().start()
        except ImportError as e:
            util.display_error(
                "Unable to launch due to missing user plugin: {}"
                .format(str(e))
            )