BetterTouchTool Simple JSON Format

BetterTouchTool 4.764 introduced a new "Simple JSON Format", which can currently be used with the predefined actions "Show Custom Context Menu (New)" and "Choose From List" and with Floating Menus. It allows to create those menus dynamically using Java Script & JSON.

How to create dynamic menus based on the Simple JSON Format

For the predefined actions "Show Custom Context Menu" and "Choose From List" you need to click the "Retrieve Content Dynamically Via Java Script" checkbox. alt text

For Floating Menus you need to set a Content Script. alt text

Then you can have a async function that returns a JSON. You can use any of BTT's scripting functions inside that Java Script (e.g. run Shell or Apple Scripts and much more). Note Make sure to set the async function to call in the separate text field.

Supported Properties

Simple example

async function retrieveJSON() {
  let items = [
    {
        "title": "trigger some shortcut",
        "icon": "sfsymbol::globe",
        "action": "shortcut::TheShortcutFromTheShortcutsApp"
    },
    {
        "title": "trigger some named trigger",
        "icon": "sfsymbol::house",
        "action": "named::TheNameOfTheBTTNamedTrigger"
    }
  ];

  return JSON.stringify(items);
}

Complex example

async function retrieveJSON() {
  let items = [
    {
        "title": "hello world",
        "icon": "sfsymbol::globe"
    },
    {
      title: "some title",
      subtitle: "some subtitle",
      subitems: [
        {
          title: "some sub-item",
          action: "named::NameOfNamedTriggerInBTT",
          icon: "sfsymbol::house::weight@@light::size@@30"
        },
        {
          title: "some sub-item2",
          icon: "base64::iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mNkYPhfz0AEYBxVSF+FAP5FDvcfRYWgAAAAAElFTkSuQmCC",
          action: "shortcut::NameOfShortcutInShortcutsApp@@OptionalInput"
        },
      ],
      icon: "sfsymbol::star::color@@B53E93",
      // this shows various forms of actions. In case you are just triggering
      // a single action, it does not need to be an array.
      action: [
        `btt::paste_text@@{"text": "hello world"}`,
        "keyboard::0", //type a
        "keyboard::11", //type b
        "keyboard::8", //type c
        "js::runShellScript({script: `say hello`})",
        {
          btt: "paste_text",
          args: {
            text: "hello world 2",
            insert_by_pasting: true,
          },
        },

        {
          shortcut: "theNameOfTheShortcut",
          input: "some optional input",
        },
      ],
    },
  ];

  return JSON.stringify(items);
}

You'll find more examples on https://community.folivora.ai for example here is an example that will list all apps / files in a specified folder: Example to list all files in a folder


Allowed Properties:

title

supported properties color & size

Examples:

{
"title": "hello::size@@30::color@@#000000"
}

Alternative syntax:

{
   "title": {
      "text": "some title",
      "size": 30,
      "color": "#000000"
   }
}

subtitle

supported properties color & size. Only works in the "choose from list action".

Examples:

{
"subtitle": "some subtitle::size@@30::color@@#000000"
}

Alternative syntax:

{
   "subtitle": {
      "text": "some subtitle",
      "size": 30,
      "color": "#000000"
   }
}

subitems

Examples:

{
    "title": "submenu",
    "subitems": [
        {
           "title": "hello"
        },
        {
           "title": "world"
        }
    ]
}

setvariable

this allows to set a variable value before the action is executed

Examples:

{
"setvariable": "variablename@@variablevalue"
}

Alternative syntax:

{
   "setvariable": {
      "name": "variablename",
      "variablevalue": "test"
   }
}

templateitemuuid

This is only for use within Floating Menus, it allows you to use the configuration of any Floating Menu Item you have created in the BTT UI as a template. You can get the UUID of any item in BTT by right-clicking it. The item used as a template can also be from a disabled menu and can even be disabled itself.

Examples:

[{
templateItemUUID: "1D974882-9376-4B09-81FC-E427F79CBD25",
"title": "some title"
},
{
templateItemUUID: "1D974882-9376-4B09-81FC-E427F79CBD25",
"title": "another title",
"icon": "sfsymbol::sun.max"
},
{
templateItemUUID: "1D974882-9376-4B09-81FC-E427F79CBD25",
"title": "third title",
"icon": "sfsymbol::house"
}
]


icon

this allows to define an icon

Supported properties: type (sfsymbol, size, path, base64, background, width, height)

Examples:

{
"icon": "sfsymbol::star"
}

Or with more options:

{
"icon": "sfsymbol::star::weight@@light::color@@#fefefe::color@@#000000::background@@#B53E93"
}

From file:

{
"icon": "path::~/Downloads/test.png::width@@40::height@@40"
}

From base64:

{
"icon": "base64::base64code"
}

Alternative syntax:

{
   "icon": {
      "type": "sfymbol",
      "sfymbol": "star",
      "weight": "light",
       "colors" : ["#000000", "#fefefe"],
      "background": "#B53E93",
      "size" : 30
   }
}

action

supported properties named, shortcut, js, keyboard, uuid, btt. Can also be an array of actions.


named

This will trigger a named trigger configured in BTT (see http://docs.folivora.ai/docs/1002_named_triggers.html )

{"title": "trigger named trigger", "action": "named::theNameOfTheNamedTrigger"},

Alternative syntax:

{
    "title": "trigger named trigger alternative", 
    "action": {
        "named": "helloworld"
    },
    "icon": "sfsymbol::star.leadinghalf.filled"
}

uuid

This will trigger any trigger configured in BTT using its UUID

{"title": "trigger via uuid", "action": "uuid::4ff033d2-8f67-490d-b281-3124d452ef07"},

Alternative syntax:

{
    "title": "trigger via UUID alternative", 
    "action": {
        "uuid": "4ff033d2-8f67-490d-b281-3124d452ef07"
    }
}

shortcut

This will trigger a shortcut configured in Apple's shortcuts app

{"title": "trigger shortcut form shortcuts app", "action": "shortcut::theNameOfTheShortcut@@someOptionalInput"},

Alternative syntax:

{
    "title": "trigger shortcut form shortcuts app alternative", 
    "action": {
        "shortcut": "theNameOfTheShortcut",
        "input": "some optional input"
    }
}

js

This will run BTT Java Script which also allows to run shell scripts or apple scripts and trigger ny of BTT's scripting functions (http://docs.folivora.ai/docs/1106_java_script.html)

E.g. run some shell script:

{"title": "say hello", "action": "js::runShellScript({script: `say hello`})"},

Or run some arbitrary apple script:

 {
      title: "show some apple script dialog",
      action: {
        js: `(async () => {

                // put the Apple Script into a string (back ticks are great for multi-line strings)
                let appleScript = \`
                    set theDialogText to "The curent date and time is " & (current date) & "."
                    set result to display dialog theDialogText
                    return result
                \`;

                // this will execute the Apple Script and store the result in the result variable.
                let result = await runAppleScript(appleScript);

                // do whatever you want with the result

                // at the end you always need to call returnToBTT to exit the script / return the value to BTT.
                returnToBTT(result);

                // it is important that this function self-executes ()
                })()
            `,
      },
    },

btt

This can run any of BTT's scripting functions (http://docs.folivora.ai/docs/1102_apple_script.html ). To see how to configure & trigger a specific action you can right-click the action in BTT and choose "copy java script to trigger action".

"action": `btt::paste_text@@{"text": "hello world"}`

Alternative syntax

{
"title": "paste item 1",
 "action": {
      "btt":"paste_text", 
      "args": {
          "text": "ddasdas",
          "insert_by_pasting": true
       }
  }
},
{
  "title": "application expose",
  "action": {
    "btt": "trigger_action",
    "args": {
      "json": {
        "BTTActionCategory": 0,
        "BTTPredefinedActionType": 6,
        "BTTPredefinedActionName": "Application Expose"
      }
    }
  }
}

keyboard

This can trigger a keyboard shortcut.

It needs to constist of comma separated modifier keys (cmd, shift, opt, fn, ctrl) and one key code at the end. A list of key codes can e.g. be found here: https://eastmanreference.com/complete-list-of-applescript-key-codes

"action": "keyboard::shift,opt,0"

Examples

Example: Get result from Apple Shortcut:

async function retrieveJSON() {

let weather = await runAppleShortcut({name: "weather", "input": ""});


let items = [
 {"title": weather},
{"title": "test item 2"},
{"title": "test item 3", "icon": "sfsymbol::star"}
]; 

 return JSON.stringify(items);

}

Example: Execute multiple actions from one item (example types abc)

async function retrieveJSON() {
    let items = [
       {
        "title": "multiple actions (type abc)", 
        "action": [
            "keyboard::0", //type a
            "keyboard::11", //type b
            "keyboard::8", //type c
        ],
        "icon": "sfsymbol::keyboard"
      },
    ]; 

    return JSON.stringify(items);

}

Example: Fetch menu from some server:

async function retrieveJSON() {
    const response = await fetch('https://folivora.ai/various/test-menu.json');

    const data = await response.json();
    const jsonString = JSON.stringify(data);
    return jsonString;

}

Example: Usage With Custom Menu Bar Items

Works with custom menubar items as well when assigning the "Show Context Menu New" action: alt text

Example: Floating Menu App Switcher

Preset download: https://share.folivora.ai/sharedPreset/55076196-7d17-4b8f-bbae-4dbd17c3ad87

Code:

async function retrieveJSON() {
    // this calls a internal BTT function to get all launched apps sorted by last usage
        let apps = await BTTActions.copyLaunchedApplicationsInFrontToBackOrder();
        let menuItems = [];
        let i=0;
         for (let app of apps) {
      // we only want to show 10 apps
         if(i>9) {break;}
         i++;
    let item = {
        templateItemUUID: "BFBD1B46-0E72-49CF-B4DB-C2CB017E82B2",
          title: "",
      action: `js::(async () => {runShellScript({script: 'open "${app.BundlePath}"'})})()`, 
      icon: `path::${app.AppIconPath}::width@@40`
    };
    menuItems.push(item);
  } 


  return JSON.stringify(menuItems);
}

results matching ""

    No results matching ""