Python Device Hacking (Gamepad)

So today I was reading an article on Hack A Day about a user who wrote a Python script to interrupt his USB Gamepad, I watched the video and realized I had a very similar gamepad laying around. One thing led to another and I found my self attempting the same sort of project.

The Gamepad I am using is a Logitec Dual Action :

gamepad

Using some of the code posted on Hackaday I quickly realized my Gamepad returned quite different result and thus needed different code.

I started with a very small Python script to print out my data in a list of character numbers:

#!/usr/bin/env python
import sys

pipe = open('/dev/input/by-id/usb-Logitech_Logitech_Dual_Action-event-joystick', 'r')
action = []

while 1:
    for character in pipe.read(1):
        action += ['%02X' % ord(character)]
        if len(action) == 8:
            print action
            action = []

To understand how the buttons worked I began by pressing and holding the number 1 button , and then pressing the Enter key on my keyboard a couple times to create spacing, I then released the number 1 button . This is what I found:

['B2', 'DD', 'E0', '4E', 'CF', 'DF', '0B', '00']
['04', '00', '04', '00', '01', '00', '09', '00']
['B2', 'DD', 'E0', '4E', 'D2', 'DF', '0B', '00']
['01', '00', '20', '01', '01', '00', '00', '00']
['B2', 'DD', 'E0', '4E', 'B4', 'E0', '0B', '00']
['00', '00', '00', '00', '00', '00', '00', '00']

['B4', 'DD', 'E0', '4E', '83', 'D2', '08', '00']
['04', '00', '04', '00', '01', '00', '09', '00']
['B4', 'DD', 'E0', '4E', '87', 'D2', '08', '00']
['01', '00', '20', '01', '00', '00', '00', '00']
['B4', 'DD', 'E0', '4E', '6C', 'D3', '08', '00']
['00', '00', '00', '00', '00', '00', '00', '00']

Looking over the list I noticed the second lines were the same, I thought this must be the pressing of the button results. To verify I tried the same code but this time I pressed the number 2 button :

['C0', 'DE', 'E0', '4E', 'C7', '43', '0B', '00']
['04', '00', '04', '00', '02', '00', '09', '00']
['C0', 'DE', 'E0', '4E', 'C9', '43', '0B', '00']
['01', '00', '21', '01', '01', '00', '00', '00']
['C0', 'DE', 'E0', '4E', 'A9', '44', '0B', '00']
['00', '00', '00', '00', '00', '00', '00', '00']

['C2', 'DE', 'E0', '4E', 'FF', 'FD', '06', '00']
['04', '00', '04', '00', '02', '00', '09', '00']
['C2', 'DE', 'E0', '4E', '02', 'FE', '06', '00']
['01', '00', '21', '01', '00', '00', '00', '00']
['C2', 'DE', 'E0', '4E', 'E2', 'FE', '06', '00']
['00', '00', '00', '00', '00', '00', '00', '00']

Again I noticed the second lines were the same, but this time the fifth element increased. How convenient the number 1 button is 01 in the fifth element where as the number 2 button is 02.

The only thing left was to create a variable to hold the state of the button, True for being pressed/held and False for being released (Not to difficult at all).

The ending code I wrote looks like this:

#!/usr/bin/env python
import sys

pipe = open('/dev/input/by-id/usb-Logitech_Logitech_Dual_Action-event-joystick', 'r')
action = []

# set all buttons to off
buttons = []
for num in range(1,9):
    vars()['b0%s' % num] = False
    buttons.append('0%s' % num)

while 1:
    # read from the device pipe and set the action
    for character in pipe.read(1):
        action += ['%02X' % ord(character)]
        if len(action) == 8:

            # if button pressed is in our buttons list
            # print what was pressed  / released
            if action[4] in buttons:
                button = action[4]
                varbutton = vars()['b%s' % button]
                if action == ['04', '00', '04', '00', button, '00', '09', '00'] and not varbutton:
                    print 'Pressed Button %s' % action[4]
                    vars()['b%s' % button] = True
                elif action == ['04', '00', '04', '00', button, '00', '09', '00'] and varbutton:
                    print 'Released Button %s' % action[4]
                    vars()['b%s' % button] = False

            # empty action list
            action = []

And the output of running it like this:

# ./game.py
Pressed Button 01
Released Button 01
Pressed Button 02
Released Button 02
Pressed Button 01
Pressed Button 02
Released Button 01
Released Button 02
Pressed Button 08
Released Button 08
Pressed Button 07
Released Button 07
Pressed Button 06
Released Button 06
Pressed Button 05
Released Button 05

Some revised code to include Arrows and removal of True/False button press flag:

#!/usr/bin/env python
import sys

pipe = open('/dev/input/by-id/usb-Logitech_Logitech_Dual_Action-event-joystick', 'r')

byte = []
while 1:
    # read from the device pipe and set the byte
    for bit in pipe.read(1):
        byte.append('%02X' % ord(bit))

        # 8 bits make a byte
        if len(byte) == 8:

            # Button 1
            if byte[2] == '20':
                button = byte[2]
                if byte == ['01', '00', button, '01', '01', '00', '00', '00']:
                    print 'Pressed Button %s' % button
                elif byte == ['01', '00', button, '01', '00', '00', '00', '00']:
                    print 'Released Button %s' % button

            # Button 2
            if byte[2] == '21':
                button = byte[2]
                if byte == ['01', '00', button, '01', '01', '00', '00', '00']:
                    print 'Pressed Button %s' % button
                elif byte == ['01', '00', button, '01', '00', '00', '00', '00']:
                    print 'Released Button %s' % button

            # Button 3
            if byte[2] == '22':
                button = byte[2]
                if byte == ['01', '00', button, '01', '01', '00', '00', '00']:
                    print 'Pressed Button %s' % button
                elif byte == ['01', '00', button, '01', '00', '00', '00', '00']:
                    print 'Released Button %s' % button

            # Button 4
            if byte[2] == '23':
                button = byte[2]
                if byte == ['01', '00', button, '01', '01', '00', '00', '00']:
                    print 'Pressed Button %s' % button
                elif byte == ['01', '00', button, '01', '00', '00', '00', '00']:
                    print 'Released Button %s' % button

            # Button 5
            if byte[2] == '24':
                button = byte[2]
                if byte == ['01', '00', button, '01', '01', '00', '00', '00']:
                    print 'Pressed Button %s' % button
                elif byte == ['01', '00', button, '01', '00', '00', '00', '00']:
                    print 'Released Button %s' % button

            # Button 6
            if byte[2] == '25':
                button = byte[2]
                if byte == ['01', '00', button, '01', '01', '00', '00', '00']:
                    print 'Pressed Button %s' % button
                elif byte == ['01', '00', button, '01', '00', '00', '00', '00']:
                    print 'Released Button %s' % button

            # Button 7
            if byte[2] == '26':
                button = byte[2]
                if byte == ['01', '00', button, '01', '01', '00', '00', '00']:
                    print 'Pressed Button %s' % button
                elif byte == ['01', '00', button, '01', '00', '00', '00', '00']:
                    print 'Released Button %s' % button

            # Button 8
            if byte[2] == '27':
                button = byte[2]
                if byte == ['01', '00', button, '01', '01', '00', '00', '00']:
                    print 'Pressed Button %s' % button
                elif byte == ['01', '00', button, '01', '00', '00', '00', '00']:
                    print 'Released Button %s' % button

            # Arror Up
            if byte[0] == '03':
                if byte == ['03', '00', '01', '00', '01', '00', '00', '00']:
                    print 'Pressed Up Arrow'

            # Arror Down
            if byte[0] == '03':
                if byte == ['03', '00', '01', '00', 'FE', '00', '00', '00']:
                    print 'Pressed Down Arrow'

            # Arror Left
            if byte[0] == '03':
                if byte == ['03', '00', '00', '00', '01', '00', '00', '00']:
                    print 'Pressed Left Arrow'

            # Arror Right
            if byte[0] == '03':
                if byte == ['03', '00', '00', '00', 'FE', '00', '00', '00']:
                    print 'Pressed Right Arrow'

            # Release Arrow
            if byte[0] == '03':
                if byte == ['03', '00', '01', '00', '80', '00', '00', '00']:
                    print 'Release Arrow'

            # empty byte
            byte = []

And a simple test to show a very common pattern:

# ./game.py
Pressed Down Arrow
Pressed Right Arrow
Release Arrow
Pressed Button 20
Released Button 20