Zuzu-Typ / XInput-Python

Simple access to the DirectX input API for Python
zlib License
28 stars 5 forks source link

No way to detect button combinations #6

Open tardy-ish opened 3 years ago

tardy-ish commented 3 years ago

So it's probably my lack of expertise with async programming speaking here but I could not figure out as to how to detect any button combinations being made on the controller, any way to do so or to implement some the filters to do the same?

Zuzu-Typ commented 3 years ago

Hi there (:

Unfortunately, XInput-Python does not offer this as a built-in feature, but it's still fairly simple to implement.

I've assembled two examples of how this can be done using the EventHandler class:

import XInput

class CustomHandler(XInput.EventHandler):

    A_AND_B_BUTTONS = XInput.BUTTON_A | XInput.BUTTON_B

    MASK = 0xFFFFFF

    def __init__(self, *controllers):
        super().__init__(*controllers, filter = CustomHandler.A_AND_B_BUTTONS)

        self.buttons_pressed = 0

    def process_button_event(self, event):
        if event.type == XInput.EVENT_BUTTON_PRESSED:
            self.buttons_pressed |= event.button_id
        else:
            self.buttons_pressed &= (CustomHandler.MASK ^ event.button_id)

        if self.buttons_pressed == CustomHandler.A_AND_B_BUTTONS:
            print("CustomHandler detected: A and B have been pressed.")

    def process_stick_event(self, event):
        pass
    def process_trigger_event(self, event):
        pass
    def process_connection_event(self, event):
        pass

class AlternativeCustomHandler(XInput.EventHandler):

    def __init__(self, *controllers):
        super().__init__(*controllers, filter = XInput.BUTTON_A | XInput.BUTTON_B)

        self.buttons_pressed = {"A" : False, "B": False}

    def process_button_event(self, event):
        if event.type == XInput.EVENT_BUTTON_PRESSED:
            self.buttons_pressed[event.button] = True
        else:
            self.buttons_pressed[event.button] = False

        if all(self.buttons_pressed.values()):
            print("AlternativeCustomHandler detected: A and B have been pressed.")

    def process_stick_event(self, event):
        pass
    def process_trigger_event(self, event):
        pass
    def process_connection_event(self, event):
        pass

main_handler = CustomHandler(0, 1, 2, 3)
alt_handler = AlternativeCustomHandler(0, 1, 2, 3)
thread = XInput.GamepadThread(main_handler)
thread.add_event_handler(alt_handler)

Each of the event handlers filter out any buttons, except for the A and B buttons, which in this example are the ones that shall be pressed together. The event handlers then keep track of the state of both buttons in some way and print a message on the console when both buttons are currently being pressed.

Admittedly, the filter/handler system isn't very great. Maybe I'll come up with a better solution some day.

Cheers, --Zuzu_Typ--