Ejemplo n.º 1
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)))
Ejemplo n.º 2
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
Ejemplo n.º 3
0
def device_available(vjoy_id):
    """Returns whether or not a device is available, i.e. can be acquired.

    :param vjoy_id id of the vjoy device to check
    :return True if the device is available, False otherwise
    """
    dev_free = VJoyInterface.GetVJDStatus(vjoy_id) == VJoyState.Free.value
    dev_acquire = VJoyInterface.AcquireVJD(vjoy_id)
    VJoyInterface.RelinquishVJD(vjoy_id)

    return dev_free & dev_acquire
Ejemplo n.º 4
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()
Ejemplo n.º 5
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()
Ejemplo n.º 6
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()
Ejemplo n.º 7
0
    def reset(self):
        """Resets the state of all inputs to their default state."""
        # Obtain the current state of all inputs
        axis_states = {}
        button_states = {}
        hat_states = {}

        for i, axis in self._axis.items():
            axis_states[i] = axis.value
        for i, button in self._button.items():
            button_states[i] = button.is_pressed
        for i, hat in self._hat.items():
            hat_states[i] = hat.direction

        # Perform reset using default vJoy functionality
        success = VJoyInterface.ResetVJD(self.vjoy_id)

        # Restore input states based on what we recorded
        if success:
            for i in self._axis:
                self._axis[i].set_absolute_value(axis_states[i])
            for i in self._button:
                self._button[i].is_pressed = button_states[i]
            for i in self._hat:
                self._hat[i].direction = hat_states[i]
        else:
            logging.getLogger("system").info(
                "Could not reset vJoy device, are we using it?")
Ejemplo n.º 8
0
def hat_count(vjoy_id):
    """Returns the number of hats of the given vJoy device.

    :param vjoy_id id of the vjoy device
    :return number of hats
    """
    return VJoyInterface.GetVJDContPovNumber(vjoy_id)
Ejemplo n.º 9
0
def button_count(vjoy_id):
    """Returns the number of buttons of the given vJoy device.

    :param vjoy_id id of the vjoy device
    :return number of buttons
    """
    return VJoyInterface.GetVJDButtonNumber(vjoy_id)
Ejemplo n.º 10
0
def device_exists(vjoy_id):
    """Returns whether or not a device exists.

    :param vjoy_id id of the vjoy device to check
    :return True if the device exists, False otherwise
    """
    state = VJoyInterface.GetVJDStatus(vjoy_id)
    return state not in [VJoyState.Missing.value, VJoyState.Unknown.value]
Ejemplo n.º 11
0
    def _init_buttons(self):
        """Retrieves all buttons present on the vJoy device and creates their
        control objects.

        :returns list of Button objects
        """
        buttons = {}
        for btn_id in range(1, VJoyInterface.GetVJDButtonNumber(self.vjoy_id)+1):
            buttons[btn_id] = Button(self, btn_id)
        return buttons
Ejemplo n.º 12
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
                ))
Ejemplo n.º 13
0
def hat_configuration_valid(vjoy_id):
    """Returns if the hats are configured properly.

    In order for hats to work properly they have to be set as continous and
    not discrete.

    Parameters
    ==========
    vjoy_id : int
        Index of the vJoy device to query

    Returns
    =======
    bool
        True if the hats are configured properly, False otherwise
    """
    continuous_count = VJoyInterface.GetVJDContPovNumber(vjoy_id)
    discrete_count = VJoyInterface.GetVJDDiscPovNumber(vjoy_id)

    return continuous_count >= discrete_count
Ejemplo n.º 14
0
def axis_count(vjoy_id):
    """Returns the number of axes of the given vJoy device.

    :param vjoy_id id of the vjoy device
    :return number of axes
    """
    count = 0
    for axis in AxisName:
        if VJoyInterface.GetVJDAxisExist(vjoy_id, axis.value) > 0:
            count += 1
    return count
Ejemplo n.º 15
0
    def invalidate(self):
        """Releases all resources claimed by this instance.

        Releases the lock on the vjoy device instance as well as terminating
        the keep alive timer.
        """
        if self.vjoy_id:
            self.reset()
            VJoyInterface.RelinquishVJD(self.vjoy_id)
            self.vjoy_id = None
            self._keep_alive_timer.cancel()
Ejemplo n.º 16
0
def device_exists(vjoy_id):
    """Returns whether or not a device exists.

    A device that exists may be acquired by a different process and thus not
    usable by Gremlin.

    :param vjoy_id id of the vjoy device to check
    :return True if the device exists, False otherwise
    """
    state = VJoyInterface.GetVJDStatus(vjoy_id)
    return state not in [VJoyState.Missing.value, VJoyState.Unknown.value]
Ejemplo n.º 17
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()
Ejemplo n.º 18
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()
Ejemplo n.º 19
0
    def _init_axes(self):
        """Retrieves all axes present on the vJoy device and creates their
        control objects.

        :returns dictionary of Axis objects
        """
        axes = {}
        for i, axis in enumerate(AxisName):
            if VJoyInterface.GetVJDAxisExist(self.vjoy_id, axis.value) > 0:
                axes[i+1] = Axis(self, axis.value)
                self._axis_names[i+1] = gremlin.common.vjoy_axis_names[i]
                self._axis_lookup[len(self._axis_names)] = i+1
                self._axis_lookup[axis] = i+1
        return axes
Ejemplo n.º 20
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)))
Ejemplo n.º 21
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)))
Ejemplo n.º 22
0
    def reset(self):
        """Resets the state of all inputs to their default state."""
        # Obtain the current state of all inputs
        axis_states = {}
        button_states = {}
        hat_states = {}

        for i, axis in self._axis.items():
            axis_states[i] = axis.value
        for i, button in self._button.items():
            button_states[i] = button.is_pressed
        for i, hat in self._hat.items():
            hat_states[i] = hat.direction

        # Perform reset using default vJoy functionality
        VJoyInterface.ResetVJD(self.vjoy_id)

        # Restore input states based on what we recorded
        for i in self._axis:
            self._axis[i].value = axis_states[i]
        for i in self._button:
            self._button[i].is_pressed = button_states[i]
        for i in self._hat:
            self._hat[i].direction = hat_states[i]