zeth / inputs

Cross-platform Python support for keyboards, mice and gamepads
BSD 3-Clause "New" or "Revised" License
269 stars 87 forks source link

Change the LEDs on a gamepad #50

Open zeth opened 6 years ago

zeth commented 6 years ago

Everything on the Xbox 360 Controller is fully supported in inputs in Linux and Windows, except changing the LEDs which appear like they could or should be programmable via the xpad driver but I haven't worked out how.

It would be cool to be able to change the LEDs on an Xbox 360 controller, then other gamepads too. To start with, I am just focusing on Linux.

What do we know?

We can send an event to /dev/input/eventN to change the caps lock led

import inputs
caps_lock = inputs.devices.keyboards[0].leds[0]
caps_lock.on()
caps_lock.off()

This sends an event in the normal evdev event format to the correct character device.

We can send an event to /dev/input/eventN to make the Gamepad rumble

import inputs
gamepad = inputs.devices.gamepads[0]
gamepad.set_vibration(1,1,1000)

On Linux, this does some interesting voodoo (in the method __get_vibration_code ) which creates a struct which is then encoded in hex and then sent as the code in the normal evdev event format to the correct character device.

We can get the current state of the gamepad led:

import inputs
gamepad_led = inputs.devices.gamepads[0].leds[0]
gamepad_led.status()

We cannot yet send an event to /dev/input/eventN to change the led, either we don't know the right voodoo or there needs a tiny bit of work in the linux driver.

We can (as root) bypass evdev and change brightness file and it will change the led. This is not the way. Inputs runs as non-root and so we need to use /dev/input/eventN like with the caps lock light and rumble.

We have some info in the Linux source code.

We know all the brightness values ('commands'):

XBOX_STYLE_LED_CONTROL = {
    0: 'off',
    1: 'all blink, then previous setting',
    2: '1/top-left blink, then on',
    3: '2/top-right blink, then on',
    4: '3/bottom-left blink, then on',
    5: '4/bottom-right blink, then on',
    6: '1/top-left on',
    7: '2/top-right on',
    8: '3/bottom-left on',
    9: '4/bottom-right on',
    10: 'rotate',
    11: 'blink, based on previous setting',
    12: 'slow blink, based on previous setting',
    13: 'rotate with two lights',
    14: 'persistent slow all blink',
    15: 'blink once, then previous setting'
}

We know (based on this) that after the evdev phrase, the actual controller is expecting 0x01, 0x03 then the command.

Apparently, this also works on Max OS X

We seem to have all or most of the pieces, how do we put it together?

So in conclusion, I don't know what struct to write to the /dev/input/eventN character device to tell the kernel xpad driver that I want to change the led 'brightness' to the correct 'command' value.

And if this is not possible, I want to change the driver so it is.

Useful Links

zeth commented 6 years ago

Somehow I need to make a friend who is an expert in the kernel side of things, maybe one of the following will know the answers: @paroj @Gottox @flibitijibibo @dtor @marcusfolkesson @auxym @TheUbuntuGuy

Gottox commented 6 years ago

Nope, I added a oneliner to the kernel. Not an expert at all.

auxym commented 6 years ago

Haha, same here. I copy-pasted a few lines and changed a device id, sorry :/

flibitijibibo commented 6 years ago

Make that three.