Ejemplo n.º 1
0
    def stop(self):
        """Stops listening to events and unloads all callbacks."""
        # Disconnect all signals
        if self._running:
            evt_lst = event_handler.EventListener()
            kb = input_devices.Keyboard()
            evt_lst.keyboard_event.disconnect(self.event_handler.process_event)
            evt_lst.joystick_event.disconnect(self.event_handler.process_event)
            evt_lst.keyboard_event.disconnect(kb.keyboard_event)
            self.event_handler.mode_changed.disconnect(
                self._vjoy_curves.mode_changed)
        self._running = False

        # Empty callback registry
        input_devices.callback_registry.clear()
        self.event_handler.clear()

        # Stop periodic events and clear registry
        input_devices.periodic_registry.stop()
        input_devices.periodic_registry.clear()

        macro.MacroManager().stop()

        # Remove all claims on VJoy devices
        joystick_handling.VJoyProxy.reset()
Ejemplo n.º 2
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)))
Ejemplo n.º 3
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))
            )