4
votes

I'm trying to write a macOS user-level driver in C for a usb-device (a pentablet with buttons).

Currently this tablet gets recognized as generic mouse and generic keyboard from the system. Since the shortcuts applied to the buttons of the pentablet are not customizeable, I'd like to write my own driver for that.

What's working:

I am able to read the raw-data with hidapi (http://www.signal11.us/oss/hidapi/) from the device, which looks something like this:

A   B    C    D    E    F    G    H
10  192  228  50   157  43   0    0

I figured out, that when I use the pen the values of the columns B-H change according to the pens position, pressure and click.

My problem:

However, I cannot figure out how to access the buttons of the device. Each time I press one of them, their hardcoded key-combination gets triggered. Since the values of column A never change, I assume that the device is still captured as a generic keyboard by the system, and so this column never shows me the currently pressed button and triggers it's key-combination.

Each time I press one of these buttons they all trigger a holding ALT/Option + Shift, additionally some of them trigger a character, and one of them triggers the volume up.

So, my approach was to use a codeless kext for preventing the system from capturing the device. But this doesn't work either - the device still gets captured by the system as a generic keyboard.

I disabled csrutil and with kextload, having my kext located in /Library/Extensions, I get a successfull message, that the kext is loaded:

Warnings:
    Personality CFBundleIdentifier differs from containing kext's (not necessarily a mistake, but rarely done):
        Tablet

Code Signing Failure: code signature is invalid
Warnings:
    Personality CFBundleIdentifier differs from containing kext's (not necessarily a mistake, but rarely done):
        Tablet

/Library/Extensions/foobartablet.kext appears to be loadable (not including linkage for on-disk libraries).
kext-dev-mode allowing invalid signature -67050 0xFFFFFFFFFFFEFA16 for kext "/Library/Extensions/foobartablet.kext"
kext signature failure override allowing invalid signature -67050 0xFFFFFFFFFFFEFA16 for kext "/Library/Extensions/foobartablet.kext"
Loading /Library/Extensions/foobartablet.kext.

Here's my info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>BuildMachineOSBuild</key>
    <string>13C64</string>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleGetInfoString</key>
    <string>1.0 Copyright © Adis Durakovic</string>
    <key>CFBundleIdentifier</key>
    <string>com.adisdurakovic.huitablet</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundlePackageType</key>
    <string>KEXT</string>
    <key>CFBundleShortVersionString</key>
    <string>Huion Tablet 1.0</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
    <key>DTCompiler</key>
    <string>com.apple.compilers.llvm.clang.1_0</string>
    <key>DTPlatformBuild</key>
    <string>5A2053</string>
    <key>DTPlatformVersion</key>
    <string>GM</string>
    <key>DTSDKBuild</key>
    <string>13A595</string>
    <key>DTSDKName</key>
    <string>macosx10.9</string>
    <key>DTXcode</key>
    <string>0501</string>
    <key>DTXcodeBuild</key>
    <string>5A2053</string>
    <key>IOKitPersonalities</key>
    <dict>
        <key>Tablet</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.kpi.iokit</string>
            <key>IOClass</key>
            <string>IOService</string>
            <key>IOProviderClass</key>
            <string>IOUSBDevice</string>
            <key>idVendor</key>
            <string>9580</string>
            <key>idProduct</key>
            <string>110</string>
            <key>bcdDevice</key>
            <string>12288</string>
            <key>IOProbeScore</key>
            <integer>200000</integer>
        </dict>
        <key>TabletNew</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.kpi.iokit</string>
            <key>IOClass</key>
            <string>IOService</string>
            <key>IOProviderClass</key>
            <string>IOUSBHostDevice</string>
            <key>idVendor</key>
            <string>9580</string>
            <key>idProduct</key>
            <string>110</string>
            <key>bcdDevice</key>
            <string>12288</string>
            <key>IOProbeScore</key>
            <integer>300000</integer>
        </dict>
    </dict>
    <key>OSBundleLibraries</key>
    <dict/>
</dict>
</plist>

And here's also my ioreg -i -w 0 -l -n "PenTablet" output which I used for device matching: https://adisdurakovic.com/pentablet.txt

What am I doing wrong here?

1
Is it possible the device is simulating another interface for the buttons so that they can be read in as separate input?Nick
@Nick, any hint for me how I could investigate further in this direction?ad_on_is
To be honest, I'm far more experienced with a pure Linux environment device wise. I only commented because I had a similar issue once with a device that had two USB logical interfaces so that it's buttons could be seen as a generic keyboard input. In Linux I would compare the contents of the USB dev files with the device unplugged vs plugged in to see the devices. I'm not sure about MacOS. Sorry I can't be more helpful.Nick
@Nick It's still a very helpful input. Maybe further researches could lead me towards your suggestion. Thank you anyway for your help, I appreciate that ;-)ad_on_is

1 Answers

1
votes

Since you mention SIP, I assume you're testing this on 10.11 or newer. Your IOProviderClass is set to IOUSBDevice - this will only work for 10.10 and older. 10.11 introduced a completely new USB stack, the new class name is IOUSBHostDevice. I know that's not what IORegistryExplorer/ioreg say: there's a translation going on somewhere to keep old userspace apps ticking over. In the kernel, drivers matching IOUSBHostDevice will take precedence over those matching IOUSBDevice. If you want to support both, you can just add an extra personality to your codeless kext. For kexts with code, you'll need to create two versions of your kext if the legacy support doesn't work in your case.

Another thing that could affect it is probe score, although in theory your idVendor + idProduct + bcdDevice rule should already have a very high score.