Generic Devices: Report repeated events even if monitored bytes don't change

Generic Devices are a great addition to the feature set. I used to use MacDial to monitor events of my SurfaceDial knob (a neat piece of hardware). From my experience hacking MacDial, I know that if I turn the knob right, it reports the same state for every "click" (a rotation of "n" degrees). Unfortunately, BTT only reports a single event, no matter how far right I turn the knob. Could you make that optional? That would make rotary knobs like the SurfaceDial actually useful for macOS.

thanks so much

ah yes I will add a function that you can call to make it recognize again. Will upload a version that includes this later!

In 4.005 you can now just call
bttGetNextEvenWithoutChange(targetDevice, reportID)
from your analyzer function, then it will get the next report even if there hasn't been a change in the data itself.

Works like a charm -- very nice, and thanks so much.

As soon as you get around to Support sending "Key Repeat" events for keyboard shortcut action, it will turn my SurfaceDial into a nice shuttle for Final Cut Pro :slight_smile:

Nice, would be great if you could share your script!

The key repeat thing is on my TODO list and I should get to it soon.

Sure, very simple, though:

function analyzeDeviceInput(targetDevice, reportID, reportDataHex) {
    let reportBuffer = buffer.Buffer.from(reportDataHex, 'hex');
    if(reportBuffer.readUInt8(1) === 0x03) {
        bttTriggerDeviceTrigger(targetDevice, 'button');
    } else if(reportBuffer.readUInt8(2) === 0x01) {
        bttTriggerDeviceTrigger(targetDevice, 'right');
    } else if(reportBuffer.readUInt8(2) === 0xff) {
        bttTriggerDeviceTrigger(targetDevice, 'left');
    }
    bttGetNextEvenWithoutChange(targetDevice, reportID)
}

The Dial actually has some other nice features, like haptic feedback and configurable sensitivity. I might try using the executeBTTCommand feature to enable those at some point.

1 Like

Thanks for sharing! Things like the Surface Dial are exactly the type of device I thought about when adding this generic device functionality. It's pretty nice being able to revive a small device with a few lines of code.

1 Like

Hi! did you ever get "button" working correctly? It seems to fire twice for me (e.g. I have it mapped to "play/pause" and pressing down and releasing causes media to play and then immediately pause again.

Maybe it's triggering for "press" and "release"? Does the data look exactly the same for both?

I think it has something to do with the next event listener:

If i remove that line, the "button" behaves as expected but the left/right rotation only triggers once (also as expected without that listener)

You could call this only for the dial:

function analyzeDeviceInput(targetDevice, reportID, reportDataHex) {
    let reportBuffer = buffer.Buffer.from(reportDataHex, 'hex');
    if(reportBuffer.readUInt8(1) === 0x03) {
        bttTriggerDeviceTrigger(targetDevice, 'button');
    } else if(reportBuffer.readUInt8(2) === 0x01) {
        bttTriggerDeviceTrigger(targetDevice, 'right');
        bttGetNextEvenWithoutChange(targetDevice, reportID)
    } else if(reportBuffer.readUInt8(2) === 0xff) {
        bttTriggerDeviceTrigger(targetDevice, 'left');
        bttGetNextEvenWithoutChange(targetDevice, reportID)
    }
}

If the button is being pressed while the wheel is still being turned, you'll want to act on both and you'll also want to be sure to call bttGetNextEvenWithoutChange() as you want to keep being notified about the wheel. So using if .. else ... else ... is generally a bad idea for buttons which aren't mutually exclusive, as multiple things could be happening at the same time and events would get lost.

The solution is to store the previous report and, in case of buttons, only act on changes. See Generic Devices: Philips Footcontrol ACC2330 for an example.

1 Like

Just replying to thank all involved in this thread. I don't need the Mac Dial app anymore and am now able to create my own dial workflow. Right now I have only one trigger for a turn of the wheel, but I'm going to try and create something that does this:

button: swich between modes
mode1 = zoom
mode2 = volume
mode3 = app switcher

1 Like