Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save 0xdevalias/3cfb3512e708b58098a315043cbaefaa to your computer and use it in GitHub Desktop.
Save 0xdevalias/3cfb3512e708b58098a315043cbaefaa to your computer and use it in GitHub Desktop.
BetterTouchTool Generic Device Trigger PoC for Razer Ouroboros gaming mouse

BetterTouchTool Generic Device Trigger PoC for Razer Ouroboros gaming mouse

BetterTouchTool Generic Device Trigger PoC for Razer Ouroboros gaming mouse.

Table of Contents

Notes

Tweets

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

Parse Device Input/Output script

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
// }

Trigger Definition

[
  {
    "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" : ""
      }
    }
  }
]

See Also

My Other Related Deepdive Gist's and Projects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment