Пример #1
0
def event_loop(configs, joy_map, tty_fd):
    event = SDL_Event()

    # keep of dict of active joystick devices as a dict of
    #  instance_id -> (config_id, SDL_Joystick object)
    active_devices = {}

    # keep an event queue populated with the current active inputs
    # indexed by joystick index, input type and input index
    # the values consist of:
    # - the event list (as taked from the event configuration)
    # - the number of times event was emitted (repeated)
    # - the last time when the event was fired
    # e.g. { event_hash -> ([event_list], repeat_no, last_fire_time) }
    event_queue = {}

    # keep track of axis previous values
    axis_prev_values = {}

    def handle_new_input(e: SDL_Event, axis_norm_value: int = 0) -> bool:
        """
        Event handling for button press/hat movement/axis movement
        Only needed when an new input is present
        Returns True when 'event_queue' is modified with a new event
        """
        dev_index = active_devices[event.jdevice.which][0]
        if e.type == SDL_JOYBUTTONDOWN:
            mapped_events = configs[dev_index].get_btn_event(
                event.jbutton.button)
            event_index = f'{dev_index}_btn{event.jbutton.button}'
        elif e.type == SDL_JOYHATMOTION:
            mapped_events = configs[dev_index].get_hat_event(
                event.jhat.hat, event.jhat.value)
            event_index = f'{dev_index}_hat{event.jhat.hat}'
        elif e.type == SDL_JOYAXISMOTION and axis_norm_value != 0:
            mapped_events = configs[dev_index].get_axis_event(
                event.jaxis.axis, axis_norm_value)
            event_index = f'{dev_index}_axis{event.jaxis.axis}'

        if mapped_events is not None:
            event_queue[event_index] = [mapped_events, 0, SDL_GetTicks()]
            return True

        return False

    running = True
    while running:
        input_started = False

        while SDL_PollEvent(byref(event)):

            if event.type == SDL_QUIT:
                running = False
                break

            if event.type == SDL_JOYDEVICEADDED:
                stick = joystick.SDL_JoystickOpen(event.jdevice.which)
                name = joystick.SDL_JoystickName(stick).decode('utf-8')
                guid = create_string_buffer(33)
                joystick.SDL_JoystickGetGUIDString(
                    joystick.SDL_JoystickGetGUID(stick), guid, 33)
                LOG.debug(
                    f'Joystick #{joystick.SDL_JoystickInstanceID(stick)} {name} added'
                )
                conf_found = False
                # try to find a configuration for the joystick
                for key, dev_conf in enumerate(configs):
                    if dev_conf.name == str(
                            name) or dev_conf.guid == guid.value.decode():
                        # Add the matching joystick configuration to the watched list
                        active_devices[joystick.SDL_JoystickInstanceID(
                            stick)] = (key, stick)
                        LOG.debug(
                            f'Added configuration for known device {configs[key]}'
                        )
                        conf_found = True
                        break

                # add the default configuration for unknown/un-configured joysticks
                if not conf_found:
                    LOG.debug(
                        f'Un-configured device "{str(name)}", mapped using generic mapping'
                    )
                    active_devices[joystick.SDL_JoystickInstanceID(stick)] = (
                        0, stick)

                # if the device has axis inputs, initialize to zero their initial position
                if joystick.SDL_JoystickNumAxes(stick) > 0:
                    axis_prev_values[joystick.SDL_JoystickInstanceID(
                        stick)] = [
                            0
                            for x in range(joystick.SDL_JoystickNumAxes(stick))
                        ]

                continue

            if event.jdevice.which not in active_devices:
                continue
            else:
                dev_index = active_devices[event.jdevice.which][0]

            if event.type == SDL_JOYDEVICEREMOVED:
                joystick.SDL_JoystickClose(
                    active_devices[event.jdevice.which][1])
                active_devices.pop(event.jdevice.which, None)
                axis_prev_values.pop(event.jdevice.which, None)
                LOG.debug(f'Removed joystick #{event.jdevice.which}')

            if event.type == SDL_JOYBUTTONDOWN:
                input_started = handle_new_input(event)

            if event.type == SDL_JOYBUTTONUP:
                event_queue.pop(f'{dev_index}_btn{event.jbutton.button}', None)

            if event.type == SDL_JOYHATMOTION:
                if event.jhat.value != SDL_HAT_CENTERED:
                    input_started = handle_new_input(event)
                else:
                    event_queue.pop(f'{dev_index}_hat{event.jhat.hat}', None)

            if event.type == SDL_JOYAXISMOTION:
                # check if the axis value went over the deadzone threshold
                if (abs(event.jaxis.value) > JS_AXIS_DEADZONE) \
                        != (abs(axis_prev_values[event.jdevice.which][event.jaxis.axis]) > JS_AXIS_DEADZONE):
                    # normalize the axis value to the movement direction or stop the input
                    if abs(event.jaxis.value) <= JS_AXIS_DEADZONE:
                        event_queue.pop(f'{dev_index}_axis{event.jaxis.axis}',
                                        None)
                    else:
                        if event.jaxis.value < 0:
                            axis_norm_value = -1
                        else:
                            axis_norm_value = 1
                        input_started = handle_new_input(
                            event, axis_norm_value)
                # store the axis current values for tracking
                axis_prev_values[event.jdevice.which][
                    event.jaxis.axis] = event.jaxis.value

        # process the current events in the queue
        if len(event_queue):
            emitted_events = filter_active_events(event_queue)
            if len(emitted_events):
                LOG.debug(f'Events emitted: {emitted_events}')
            # send the events mapped key code(s) to the terminal
            for k in emitted_events:
                if k in joy_map:
                    for c in joy_map[k]:
                        fcntl.ioctl(tty_fd, termios.TIOCSTI, c)

        SDL_Delay(JS_POLL_DELAY)
Пример #2
0
 def test_SDL_JoystickInstanceID(self):
     for index in range(self.jcount):
         stick = joystick.SDL_JoystickOpen(index)
         ret = joystick.SDL_JoystickInstanceID(stick)
         assert ret > 0
         joystick.SDL_JoystickClose(stick)