I'm trying to use a PS2 Guitar Hero II controller on PC/Linux. After trying out multiple Playstation-to-usb adapters, I've finally found one that does not cause any input lag.

However I've encountered a problem with detecting all buttons under linux, as discussed in the linux-input mailing list thread.


  • All buttons are detected, but the D-pad (strum up/down) is incorrectly mapped to the same axis as the "Whammy bar". This is not game-breaking, but inconvenient.


  • Linux detects the controller as ID 054c:0268 Sony Corp. Batoh Device / PlayStation 3 Controller, having 13 buttons and 6 axes.

  • Some buttons cause no events in /dev/input/jsX

  • The non-working buttons do cause HID-events, detected in /dev/hidrawX.

Now, I understand that this is a bug, and I should just wait for a fix to the driver. While the fix is processing, I'd like to find a workaround.

Could I easily write some udev rule that could map raw HID-events to input events?

Also, I've captured the USB handshake process using wireshark under windows.

  • What about using QJoyPad 4, a fork of QJoyPad to remap the buttons of your controller while a fix isn't available to the drivers? - github.com/panzi/qjoypad
    – user34720
    Mar 20, 2019 at 16:59
  • Looks like QJoyPad uses joystick devices (e.g. /dev/input/js0), which don't show anything when the missing buttons are pressed. I'm going to need something that can parse the raw HID-data. Mar 21, 2019 at 17:12

1 Answer 1


I got it working by using hidapi for python. In the end it was very easy, I was just missing the tool.

Here is the full script should anyone need guidance:

from __future__ import print_function

import hid
import time
import uinput

    'green': uinput.BTN_0,
    'red': uinput.BTN_1,
    'yellow': uinput.BTN_2,
    'blue': uinput.BTN_3,
    'orange': uinput.BTN_4,
    'tilt': uinput.BTN_SELECT,  # SELECT
    'start': uinput.BTN_START,  # START
    'select': uinput.BTN_SELECT,  # SELECT
    'whammy': uinput.ABS_X,  # WHAMMY
    'strumdown': uinput.BTN_DPAD_DOWN,
    'strumup': uinput.BTN_DPAD_UP,

DEVICE = uinput.Device(MAPPING.values())

# enumerate USB devices

for d in hid.enumerate():
    keys = list(d.keys())
    for key in keys:
        print("%s : %s" % (key, d[key]))

# try opening a device, then perform write and read

def diff(new_arr, old_arr):
    for i in range(len(new_arr)):
        if new_arr[i] != old_arr[i]:
            yield (i, new_arr[i]) 

    print("Opening the device")

    h = hid.device()
    h.open(0x054c, 0x0268)  # VendorID/ProductID

    print("Manufacturer: %s" % h.get_manufacturer_string())
    print("Product: %s" % h.get_product_string())
    print("Serial No: %s" % h.get_serial_number_string())

    # enable non-blocking mode

    # write some data to the device
    print("Write the data")
    h.write([0, 63, 35, 35] + [0] * 61)

    # wait

    # read back the answer
    print("Read the data")
    previous = None
    INPUT = {
        'green': False,
        'red': False,
        'yellow': False,
        'blue': False,
        'orange': False,
        'tilt': False,
        'start': False,
        'select': False,
        'whammy': False,
        'strumdown': False,
        'strumup': False,

    def set_input(key, val, tmp):
        prev = INPUT[key]
        if tmp >= val:
            tmp -= val
            INPUT[key] = True
            INPUT[key] = False

        if prev != INPUT[key]:
            # SEND EVENT
            DEVICE.emit(MAPPING[key], INPUT[key])

        return tmp

    counter = 0
    while True:
            d = h.read(64)
            counter += 1
            if d:
                if previous and d != previous:
                    for ret in diff(d, previous):
                        if ret[0] == 7:
                            DEVICE.emit(MAPPING['whammy'], ret[1])

                        if ret[0] == 2:
                            tmp = ret[1] - 128
                            tmp = set_input('strumdown', 64, tmp)
                            tmp = set_input('strumup', 16, tmp)
                            tmp = set_input('start', 8, tmp)
                            tmp = set_input('select', 1, tmp)

                        if ret[0] == 3:
                            tmp = ret[1]
                            tmp = set_input('orange', 128, tmp)
                            tmp = set_input('blue', 64, tmp)
                            tmp = set_input('red', 32, tmp)
                            tmp = set_input('yellow', 16, tmp)
                            tmp = set_input('green', 2, tmp)
                            tmp = set_input('tilt', 1, tmp)

                previous = d
        except KeyboardInterrupt:
        print(counter, end="\r")
        # print(INPUT)

    print("Closing the device")

except IOError as ex:
    print("You probably don't have the hard coded device. Update the hid.device line")
    print("in this script with one from the enumeration list output above and try again.")


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.