https://updates.folivora.ai/bettertouchtool_release_notes.html
-
BetterTouchTool >= 4.0 (January, 30, 2023)
-
New Trigger Section: "Generic Devices". With this it becomes possible to make most input devices (e.g. remotes, special mice, buttons etc.) work with BTT, using some Java Script.
-
https://docs.folivora.ai/docs/1500_generic_devices.html
Using this feature for the Razer Ouroboros: https://twitter.com/_devalias/status/1621421090101948416
Using this feature for the Native Instruments Traktor F1: https://twitter.com/_devalias/status/1621428879721373696
let isButtonDown = false
// Enter your input analyzer script here.
// Do not change the function signatures
function analyzeDeviceInput(targetDevice, reportID, reportDataHex) {
let reportBuffer = buffer.Buffer.from(reportDataHex, 'hex');
// the values you see above are in hex format. To read such a byte
// use readUInt8(index).
if (reportID === 0) {
let scrollByte = reportBuffer.readUInt8(3)
let isScrolling = scrollByte === 0x01 || scrollByte === 0xff
if (reportBuffer.readUInt8(0) === 0x01) {
isButtonDown = true
log('leftButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'leftButtonDown')
}
else if (reportBuffer.readUInt8(0) === 0x02) {
isButtonDown = true
log('rightButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'rightButtonDown')
}
else if (reportBuffer.readUInt8(0) === 0x04) {
isButtonDown = true
log('middleButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'middleButtonDown')
}
else if (reportBuffer.readUInt8(0) === 0x10) {
isButtonDown = true
log('forwardThumbButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'forwardThumbButtonDown')
}
else if (reportBuffer.readUInt8(0) === 0x08) {
isButtonDown = true
log('backThumbButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'backThumbButtonDown')
}
else if (reportBuffer.readUInt8(0) === 0x00 && isButtonDown && !isScrolling) {
isButtonDown = false
log('buttonUp')
bttTriggerDeviceTrigger(targetDevice, 'buttonUp')
}
// if (reportBuffer.readUInt8(3) === 0x01) {
// log('scrollForward')
// }
// else if (reportBuffer.readUInt8(3) === 0xff) {
// log('scrollBackward')
// }
}
else if (reportID === 4) {
if (reportBuffer.readUInt8(1) === 0x20) {
log('middleSensitivityTopButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'middleSensitivityTopButtonDown')
}
else if (reportBuffer.readUInt8(1) === 0x21) {
log('middleSensitivityBottomButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'middleSensitivityBottomButtonDown')
}
else if (reportBuffer.readUInt8(1) === 0x25) {
log('leftClutchButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'leftClutchButtonDown')
}
else if (reportBuffer.readUInt8(1) === 0x24) {
log('rightClutchButtonDown')
bttTriggerDeviceTrigger(targetDevice, 'rightClutchButtonDown')
}
else if (reportBuffer.readUInt8(1) === 0x00) {
log('reportID4ButtonUp')
bttTriggerDeviceTrigger(targetDevice, 'reportID4ButtonUp')
}
}
}
// Advanced, optional. Use if you want to trigger commands that send data to
// the device, from a BTT predefined action.
// See https://docs.folivora.ai/1500_generic_devices.html
// async function executeBTTCommand(targetDevice, commandName, commandInput) {
// log("execute command: " + commandName)
// switch(commandName) {
// case "exampleCommand": {
// // send any hex string to the device
// let deviceResponse = await bttSendDataToDevice({
// BTTActionSendDataTargetDevice: targetDevice,
// BTTActionSendDataData: 'FEEDC0DE',
// BTTActionSendDataReportType: 1,
// BTTActionSendDataResponseType: -1,
// BTTActionSendDataResponsePrefix: ''
// });
// break;
// }
// }
// return 'done executing ' + commandName
// }
[
{
"BTTGestureNotes" : "Razer Ouroboros",
"BTTTriggerType" : 763,
"BTTTriggerTypeDescription" : "Generic Device & Input Analyzer",
"BTTTriggerClass" : "BTTTriggerTypeGenericDevice",
"BTTPredefinedActionType" : -1,
"BTTPredefinedActionName" : "No Action",
"BTTEnabled2" : 1,
"BTTAlternateModifierKeys" : 0,
"BTTRepeatDelay" : 0,
"BTTUUID" : "3DE7DF79-6C7B-4844-A3D6-66907EAEC55A",
"BTTNotesInsteadOfDescription" : 0,
"BTTEnabled" : 1,
"BTTModifierMode" : 0,
"BTTOrder" : 0,
"BTTDisplayOrder" : 0,
"BTTGenericDeviceConfiguration" : {
"BTTGenericDeviceUsagePair4" : {
"BTTGenericDeviceUsagePage" : "",
"BTTGenericDeviceUsage" : ""
},
"BTTGenericDeviceVendorID" : "0x1532",
"BTTGenericDeviceWatchedBytes" : {
"0" : [
0,
3
],
"4" : [
1
]
},
"BTTGenericDeviceUsagePair3" : {
"BTTGenericDeviceUsagePage" : "",
"BTTGenericDeviceUsage" : ""
},
"BTTGenericDeviceActiveReports" : {
"0" : true,
"4" : true
},
"BTTGenericDeviceProvidedTriggers" : "leftButtonDown\nrightButtonDown\nmiddleButtonDown\nforwardThumbButtonDown\nbackThumbButtonDown\nbuttonUp\nmiddleSensitivityTopButtonDown\nmiddleSensitivityBottomButtonDown\nleftClutchButtonDown\nrightClutchButtonDown",
"BTTGenericDeviceUsagePair2" : {
"BTTGenericDeviceUsagePage" : "",
"BTTGenericDeviceUsage" : ""
},
"BTTGenericDeviceProductID" : "0x32",
"BTTGenericDeviceName" : "Razer Ouroboros",
"BTTGenericDeviceScript" : "let isButtonDown = false\n\n\/\/ Enter your input analyzer script here. \n\/\/ Do not change the function signatures\nfunction analyzeDeviceInput(targetDevice, reportID, reportDataHex) {\n\tlet reportBuffer = buffer.Buffer.from(reportDataHex, 'hex');\n \/\/ the values you see above are in hex format. To read such a byte\n \/\/ use readUInt8(index).\n \n if (reportID === 0) {\n let scrollByte = reportBuffer.readUInt8(3)\n let isScrolling = scrollByte === 0x01 || scrollByte === 0xff\n\n if (reportBuffer.readUInt8(0) === 0x01) {\n isButtonDown = true\n log('leftButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'leftButtonDown')\n }\n else if (reportBuffer.readUInt8(0) === 0x02) {\n isButtonDown = true\n log('rightButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'rightButtonDown')\n }\n else if (reportBuffer.readUInt8(0) === 0x04) {\n isButtonDown = true\n log('middleButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'middleButtonDown')\n }\n else if (reportBuffer.readUInt8(0) === 0x10) {\n isButtonDown = true\n log('forwardThumbButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'forwardThumbButtonDown')\n }\n else if (reportBuffer.readUInt8(0) === 0x08) {\n isButtonDown = true\n log('backThumbButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'backThumbButtonDown')\n }\n else if (reportBuffer.readUInt8(0) === 0x00 && isButtonDown && !isScrolling) {\n isButtonDown = false\n log('buttonUp')\n\n bttTriggerDeviceTrigger(targetDevice, 'buttonUp')\n }\n\n \/\/ if (reportBuffer.readUInt8(3) === 0x01) {\n \/\/ log('scrollForward')\n \/\/ }\n \/\/ else if (reportBuffer.readUInt8(3) === 0xff) {\n \/\/ log('scrollBackward')\n \/\/ }\n }\n else if (reportID === 4) {\n if (reportBuffer.readUInt8(1) === 0x20) {\n log('middleSensitivityTopButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'middleSensitivityTopButtonDown')\n }\n else if (reportBuffer.readUInt8(1) === 0x21) {\n log('middleSensitivityBottomButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'middleSensitivityBottomButtonDown')\n }\n else if (reportBuffer.readUInt8(1) === 0x25) {\n log('leftClutchButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'leftClutchButtonDown')\n }\n else if (reportBuffer.readUInt8(1) === 0x24) {\n log('rightClutchButtonDown')\n\n bttTriggerDeviceTrigger(targetDevice, 'rightClutchButtonDown')\n }\n else if (reportBuffer.readUInt8(1) === 0x00) {\n log('reportID4ButtonUp')\n\n bttTriggerDeviceTrigger(targetDevice, 'reportID4ButtonUp')\n }\n }\n}\n\n\/\/ Advanced, optional. Use if you want to trigger commands that send data to\n\/\/ the device, from a BTT predefined action.\n\/\/ See https:\/\/docs.folivora.ai\/1500_generic_devices.html\n\/\/ async function executeBTTCommand(targetDevice, commandName, commandInput) {\n\/\/ log(\"execute command: \" + commandName)\n\/\/ switch(commandName) {\n\/\/ case \"exampleCommand\": {\n\/\/ \/\/ send any hex string to the device\n\/\/ let deviceResponse = await bttSendDataToDevice({\n\/\/ BTTActionSendDataTargetDevice: targetDevice,\n\/\/ BTTActionSendDataData: 'FEEDC0DE',\n\/\/ BTTActionSendDataReportType: 1,\n\/\/ BTTActionSendDataResponseType: -1,\n\/\/ BTTActionSendDataResponsePrefix: ''\n\/\/ }); \n\/\/ break;\n\/\/ }\n\/\/ }\n\/\/ return 'done executing ' + commandName\n\/\/ }",
"BTTGenericDeviceSelectedTab" : 1,
"BTTGenericDeviceDropdownSelection" : {
"manufacturer" : "Razer",
"product" : "Razer Ouroboros",
"productID" : 50,
"usagePairs" : [
{
"DeviceUsagePage" : 1,
"DeviceUsage" : 6
},
{
"DeviceUsagePage" : 12,
"DeviceUsage" : 1
},
{
"DeviceUsagePage" : 1,
"DeviceUsage" : 128
},
{
"DeviceUsagePage" : 1,
"DeviceUsage" : 0
}
],
"vendorID" : 5426
},
"BTTGenericDeviceUsagePair1" : {
"BTTGenericDeviceUsagePage" : "",
"BTTGenericDeviceUsage" : ""
}
}
}
]