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.
For Floating Menus you need to set a Content Script.
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:
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);
}