Beispiel #1
0
    def axis(self, axis_id=None, linear_index=None):
        """Returns the axis object associated with the provided index.

        :param axis_id actual id of the axis which may not be contiguous
        :param linear_index linear index of the axis independent of true ids
        :return Axis object corresponding to the provided index
        """
        if axis_id is not None:
            axis_id = VJoy.axis_equivalence.get(axis_id, axis_id)
            if not self.is_axis_valid(axis_id=axis_id):
                raise VJoyError(
                    "Invalid axis index requested - {}".format(
                        _error_string(self.vjoy_id, axis_id, "")
                    )
                )
            return self._axis[axis_id]
        elif linear_index is not None:
            if not self.is_axis_valid(linear_index=linear_index):
                raise VJoyError(
                    "Invalid linear index for axis lookup provided - {}".format(
                        _error_string(self.vjoy_id, linear_index, "")
                    )
                )
            return self._axis[self._axis_lookup[linear_index]]
        else:
            raise VJoyError("No vjoy_id or linear_index provided")
Beispiel #2
0
    def axis_name(self, axis_id=None, linear_index=None):
        """Returns the textual name of the requested axis.

        As there are two ways to refer to an axis, absolute in terms of the
        AxisName enum and relative, i.e. number based on the total number of
        axes present. This method deals with both methods and the user
        needs to request the correct one.

        :param axis_id absolute index of the axis whose name to return
        :param linear_index relative index of the axis whose name to return
        :return name of the provided axis
        """
        if axis_id is not None:
            axis_id = VJoy.axis_equivalence.get(axis_id, axis_id)
            if not self.is_axis_valid(axis_id=axis_id):
                raise VJoyError("Invalid axis index requested - {}".format(
                    _error_string(self.vjoy_id, axis_id, "")))
            return self._axis_names[axis_id]
        elif linear_index is not None:
            if not self.is_axis_valid(linear_index=linear_index):
                raise VJoyError(
                    "Invalid linear index for axis lookup provided - {}".
                    format(_error_string(self.vjoy_id, linear_index, "")))
            return self._axis_names[self._axis_lookup[linear_index]]
        else:
            raise VJoyError("No vjoy_id or linear_index provided")
Beispiel #3
0
    def _set_discrete_direction(self, direction):
        """Sets the direction of a discrete hat.

        :param direction the direction of the hat
        """
        if direction not in Hat.to_discrete_direction:
            raise VJoyError("Invalid direction specified - {}".format(
                _error_string(self.vjoy_id, self.axis_id, self._direction)))

        self._direction = direction
        if not VJoyInterface.SetDiscPov(Hat.to_discrete_direction[direction],
                                        self.vjoy_id, self.hat_id):
            raise VJoyError("Failed to set hat direction - {}".format(
                _error_string(self.vjoy_id, self.axis_id, self._direction)))
Beispiel #4
0
    def _set_continuous_direction(self, direction):
        """Sets the direction of a continuous hat.

        :param direction the angle in degree of the hat
        """
        if direction not in Hat.to_continuous_direction:
            raise VJoyError("Invalid direction specified - {}".format(
                _error_string(self.vjoy_id, self.axis_id, direction)))

        self._direction = direction
        if not VJoyInterface.SetContPov(Hat.to_continuous_direction[direction],
                                        self.vjoy_id, self.hat_id):
            raise VJoyError("Failed to set hat direction - {}".format(
                _error_string(self.vjoy_id, self.axis_id, self._direction)))
Beispiel #5
0
    def __init__(self, vjoy_id):
        """Creates a new object.

        :param vjoy_id id of the vJoy device to initialize.
        """
        self.vjoy_id = None

        if not VJoyInterface.vJoyEnabled():
            logging.getLogger("system").error("vJoy is not currently running")
            raise VJoyError("vJoy is not currently running")
        if VJoyInterface.GetvJoyVersion() != 0x218:
            logging.getLogger("system").error(
                "Running incompatible vJoy version, 2.1.8 required"
            )
            raise VJoyError("Running incompatible vJoy version, 2.1.8 required")
        elif VJoyInterface.GetVJDStatus(vjoy_id) != VJoyState.Free.value:
            logging.getLogger("system").error(
                "Requested vJoy device is not available - vid: {}".format(vjoy_id)
            )
            raise VJoyError(
                "Requested vJoy device is not available - vid: {}".format(vjoy_id)
            )
        elif not VJoyInterface.AcquireVJD(vjoy_id):
            logging.getLogger("system").error(
                "Failed to acquire the vJoy device - vid: {}".format(vjoy_id)
            )
            raise VJoyError(
                "Failed to acquire the vJoy device - vid: {}".format(vjoy_id)
            )

        self.vjoy_id = vjoy_id
        self.pid = os.getpid()

        # Initialize all controls
        self._axis_lookup = {}
        self._axis_names = {}
        self._axis = self._init_axes()
        self._button = self._init_buttons()
        self._hat = self._init_hats()

        # Timestamp of the last time the device was used
        self._last_active = time.time()
        self._keep_alive_timer = threading.Timer(
            VJoy.keep_alive_timeout,
            self._keep_alive
        )
        self._keep_alive_timer.start()

        # Reset all controls
        self.reset()
Beispiel #6
0
    def _init_hats(self):
        """Retrieves all hats present on the vJoy device and creates their
        control objects.

        A single device can either have continuous or discrete hats, but
        not both at the same time.

        :returns list of Hat objects
        """
        hats = {}
        # We can't use discrete hats as such their existence is considered
        # an error
        if VJoyInterface.GetVJDDiscPovNumber(self.vjoy_id) > 0:
            error_msg = "vJoy is configured incorrectly. \n\n" \
                    "Please ensure hats are configured as 'Continuous' " \
                    "rather then '4 Directions'."
            logging.getLogger("system").error(error_msg)
            raise VJoyError(error_msg)
        # for hat_id in range(1, VJoyInterface.GetVJDDiscPovNumber(self.vjoy_id)+1):
        #     hats[hat_id] = Hat(self, hat_id, HatType.Discrete)
        for hat_id in range(
                1,
                VJoyInterface.GetVJDContPovNumber(self.vjoy_id) + 1):
            hats[hat_id] = Hat(self, hat_id, HatType.Continuous)
        return hats
Beispiel #7
0
    def set_absolute_value(self, value):
        """Sets the position of the axis based on a value between [-1, 1].

        In comparison to the value setter this function bypasses the
        deadzone and response curve settings.

        :param value the position of the axis in the range [-1, 1]
        """
        # Log an error on invalid data but continue processing by clamping
        # the values in the next step
        if 1.0 - abs(value) < -0.001:
            logging.getLogger("system").warning(
                "Wrong data type provided, has to be float in [-1, 1],"
                " provided value was {:.2f}".format(value))

        # Normalize value to [-1, 1] and apply response curve and deadzone
        # settings
        self._value = value

        if not VJoyInterface.SetAxis(
                int(self._half_range + self._half_range * self._value),
                self.vjoy_id, self.axis_id):
            raise VJoyError("Failed setting axis value - {}".format(
                _error_string(self.vjoy_id, self.axis_id, self._value)))
        self.vjoy_dev.used()
Beispiel #8
0
    def value(self, value):
        """Sets the position of the axis based on a value between [-1, 1].

        :param value the position of the axis in the range [-1, 1]
        """
        self.vjoy_dev.ensure_ownership()

        # Log an error on invalid data but continue processing by clamping
        # the values in the next step
        if 1.0 - abs(value) < -0.001:
            logging.getLogger("system").warning(
                "Wrong data type provided, has to be float in [-1, 1],"
                " provided value was {:.2f}".format(value))

        # Normalize value to [-1, 1] and apply response curve and deadzone
        # settings
        self._value = self._response_curve_fn(
            self._deadzone_fn(min(1.0, max(-1.0, value))))

        if not VJoyInterface.SetAxis(
                int(self._half_range + self._half_range * self._value),
                self.vjoy_id, self.axis_id):
            raise VJoyError("Failed setting axis value - {}".format(
                _error_string(self.vjoy_id, self.axis_id, self._value)))
        self.vjoy_dev.used()
Beispiel #9
0
    def __init__(self, vjoy_dev, axis_id):
        """Creates a new object.

        :param vjoy_dev the vJoy device this axis belongs to
        :param axis_id the id of the axis this object controls
        """
        self.vjoy_dev = vjoy_dev
        self.vjoy_id = vjoy_dev.vjoy_id
        self.axis_id = axis_id
        self._value = 0.0

        # Retrieve axis minimum and maximum values
        tmp = ctypes.c_ulong()
        VJoyInterface.GetVJDAxisMin(self.vjoy_id, self.axis_id,
                                    ctypes.byref(tmp))
        self._min_value = tmp.value
        VJoyInterface.GetVJDAxisMax(self.vjoy_id, self.axis_id,
                                    ctypes.byref(tmp))
        self._max_value = tmp.value
        self._half_range = int(self._max_value / 2)

        self._deadzone_fn = lambda x: deadzone(x, -1.0, -0.0, 0.0, 1.0)
        self._response_curve_fn = lambda x: x

        # If this is not the case our value setter needs to change
        if self._min_value != 0:
            raise VJoyError("vJoy axis minimum value is not 0  - {}".format(
                _error_string(self.vjoy_id, self.axis_id, self._min_value)))
Beispiel #10
0
    def button(self, index):
        """Returns the axis object associated with the provided index.

        :param index the index of the button to return
        :return Button object corresponding to the provided index
        """
        if index not in self._button:
            raise VJoyError("Invalid button index requested: {:d}".format(index))
        return self._button[index]
Beispiel #11
0
    def hat(self, index):
        """Returns the hat object associated with the provided index.

        :param index the index of the hat to return
        :return Hat object corresponding to the provided index
        """
        if index not in self._hat:
            raise VJoyError("Invalid hat index requested: {:d}".format(index))
        return self._hat[index]
Beispiel #12
0
    def axis_id(self, linear_index):
        """Returns the absolute axis id corresponding to the relative one.

        :param linear_index the relative index of the desired axis
        :return absolute id of the axis
        """
        if not self.is_axis_valid(linear_index=linear_index):
            raise VJoyError(
                "Invalid linear index for axis lookup provided - {}".format(
                    _error_string(self.vjoy_id, linear_index, "")))

        return self._axis_lookup[linear_index]
Beispiel #13
0
    def direction(self, direction):
        """Sets the direction of the hat.

        :param direction the new direction of the hat
        """
        if self.hat_type == HatType.Discrete:
            self._set_discrete_direction(direction)
        elif self.hat_type == HatType.Continuous:
            self._set_continuous_direction(direction)
        else:
            raise VJoyError("Invalid hat type specified")
        self.vjoy_dev.used()
Beispiel #14
0
    def is_axis_valid(self, axis_id=None, linear_index=None):
        """Returns whether or not an axis is valid.

        :param axis_id actual id of the axis which may not be contiguous
        :param linear_index linear index of the axis independent of true ids
        :return True if the axis is valid, False otherwise
        """
        if axis_id is not None:
            return axis_id in self._axis
        elif linear_index is not None:
            return linear_index in self._axis_lookup
        else:
            raise VJoyError("No vjoy_id or linear_index provided")
Beispiel #15
0
    def is_pressed(self, is_pressed):
        """Sets the state of the button.

        :param is_pressed True if the button is pressed, False otherwise
        """
        assert (isinstance(is_pressed, bool))
        self.vjoy_dev.ensure_ownership()
        self._is_pressed = is_pressed
        if not VJoyInterface.SetBtn(self._is_pressed, self.vjoy_id,
                                    self.button_id):
            raise VJoyError("Failed setting button value - {}".format(
                _error_string(self.vjoy_id, self.button_id, self._is_pressed)))
        self.vjoy_dev.used()
Beispiel #16
0
    def is_pressed(self, is_pressed):
        """Sets the state of the button.

        :param is_pressed True if the button is pressed, False otherwise
        """
        assert(isinstance(is_pressed, bool))
        self._is_pressed = is_pressed
        if not VJoyInterface.SetBtn(
                self._is_pressed,
                self.vjoy_id,
                self.button_id
        ):
            raise VJoyError("Failed updating button state")
        self.vjoy_dev.used()
Beispiel #17
0
    def direction(self, direction):
        """Sets the direction of the hat.

        :param direction the new direction of the hat
        """
        self.vjoy_dev.ensure_ownership()

        if self.hat_type == HatType.Discrete:
            self._set_discrete_direction(direction)
        elif self.hat_type == HatType.Continuous:
            self._set_continuous_direction(direction)
        else:
            raise VJoyError("Invalid hat type specified - {}".format(
                _error_string(self.vjoy_id, self.axis_id, self.direction)))
        self.vjoy_dev.used()
Beispiel #18
0
    def ensure_ownership(self):
        """Ensure this devices is still owned by the process.

        This object can only be constructed if it successfully acquires the
        vjoy device and destroys itself when relinquishing control. Therefore,
        it cannot ever not own the vJoy device.

        Under certain circumstances the vJoy devices are reset (issue #129).
        By checking for ownership and reacquiring if needed this can be solved.
        """
        if self.pid != VJoyInterface.GetOwnerPid(self.vjoy_id):
            if not VJoyInterface.AcquireVJD(self.vjoy_id):
                logging.getLogger("system").error(
                    "Failed to re-acquire the vJoy device - vid: {}".format(
                        self.vjoy_id
                ))
                raise VJoyError(
                    "Failed to re-acquire the vJoy device - vid: {}".format(
                        self.vjoy_id
                ))