0

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.

Windows

  • 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

  • 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 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. – Eero Vilpponen Mar 21 at 17:12
0

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

MAPPING = {
    '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())
    keys.sort()
    for key in keys:
        print("%s : %s" % (key, d[key]))
    print()

# 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]) 


try:
    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
    h.set_nonblocking(1)

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

    # wait
    time.sleep(0.05)

    # 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
        else:
            INPUT[key] = False

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

        return tmp

    counter = 0
    while True:
        try:
            time.sleep(0.001)
            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
            else:
                continue
        except KeyboardInterrupt:
            break
        print(counter, end="\r")
        # print(INPUT)

    print("Closing the device")
    h.close()

except IOError as ex:
    print(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.")

print("Done")

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.