Just a quick demo of what is already possible with existing functionality (might require current alpha version). Maybe useful as reference.
Putting this into a floating webview action, will list all of the shortcuts and their actions like this:
It could easily be styled with some CSS.
<html>
<head>
<script>
async function BTTWindowWillBecomeVisible() {
console.log("loading triggers");
const allKeyboardShortcutsJSONString = await callBTT("get_triggers", {
trigger_type: "BTTTriggerTypeKeyboardShortcut",
});
const allTriggersJSONArray = JSON.parse(allKeyboardShortcutsJSONString);
let allKeyboardShortcuts = "";
for (const trigger of allTriggersJSONArray) {
if (trigger.BTTShortcutModifierKeys) {
const shortcut = `<div><span><b>${
trigger?.BTTTriggerConfig?.BTTLeftRightModifierDifferentiation
? getModifiersForBitmask(
trigger.BTTAdditionalConfiguration,
true
)
: getModifiersForBitmask(trigger.BTTShortcutModifierKeys, false)
}${getKeycodeStringForKeycode(
trigger.BTTShortcutKeyCode
)}</b></span> <span>${getActionNameForID(
trigger.BTTPredefinedActionType,
trigger
)}</span></div>`;
allKeyboardShortcuts = allKeyboardShortcuts + shortcut;
}
}
document.getElementById("triggerList").innerHTML = allKeyboardShortcuts;
}
function getKeycodeStringForKeycode(keycode) {
switch (keycode) {
case 0x00: {
return "A";
}
case 0x01: {
return "S";
}
case 0x02: {
return "D";
}
case 0x03: {
return "F";
}
case 0x04: {
return "H";
}
case 0x05: {
return "G";
}
case 0x06: {
return "Z";
}
case 0x07: {
return "X";
}
case 0x08: {
return "C";
}
case 0x09: {
return "V";
}
case 0x0b: {
return "B";
}
case 0x0c: {
return "Q";
}
case 0x0d: {
return "W";
}
case 0x0e: {
return "E";
}
case 0x0f: {
return "R";
}
case 0x10: {
return "Y";
}
case 0x11: {
return "T";
}
case 0x12: {
return "1";
}
case 0x13: {
return "2";
}
case 0x14: {
return "3";
}
case 0x15: {
return "4";
}
case 0x16: {
return "6";
}
case 0x17: {
return "5";
}
case 0x18: {
return "=";
}
case 0x19: {
return "9";
}
case 0x1a: {
return "7";
}
case 0x1b: {
return "-";
}
case 0x1c: {
return "8";
}
case 0x1d: {
return "0";
}
case 0x1e: {
return "]";
}
case 0x1f: {
return "O";
}
case 0x20: {
return "U";
}
case 0x21: {
return "[";
}
case 0x22: {
return "I";
}
case 0x23: {
return "P";
}
case 0x25: {
return "L";
}
case 0x26: {
return "J";
}
case 0x27: {
return '"';
}
case 0x28: {
return "K";
}
case 0x29: {
return ";";
}
case 0x2a: {
return "\\";
}
case 0x2b: {
return ",";
}
case 0x2c: {
return "/";
}
case 0x2d: {
return "N";
}
case 0x2e: {
return "M";
}
case 0x2f: {
return ".";
}
case 0x32: {
return "?";
}
case 0x41: {
return ".";
}
case 0x43: {
return "*";
}
case 0x45: {
return "+";
}
case 0x47: {
return "?";
}
case 0x4b: {
return "%";
}
case 0x4c: {
return "return";
}
case 0x4e: {
return "-";
}
case 0x51: {
return "=";
}
case 0x52: {
return "0";
}
case 0x53: {
return "1";
}
case 0x54: {
return "2";
}
case 0x55: {
return "3";
}
case 0x56: {
return "4";
}
case 0x57: {
return "5";
}
case 0x58: {
return "6";
}
case 0x59: {
return "7";
}
case 0x5b: {
return "8";
}
case 0x5c: {
return "9";
}
case 0x24: {
return "Return";
}
case 0x30: {
return "Tab";
}
case 0x31: {
return "Space";
}
case 0x33: {
return "Delete";
}
case 0x35: {
return "Escape";
}
case 0x37: {
return "Command";
}
case 0x38: {
return "Shift";
}
case 0x39: {
return "CapsLock";
}
case 0x3a: {
return "Option";
}
case 0x3b: {
return "Control";
}
case 0x3c: {
return "RightShift";
}
case 0x3d: {
return "RightOption";
}
case 0x3e: {
return "RightControl";
}
case 0x3f: {
return "Function";
}
case 0x40: {
return "F17";
}
case 0x48: {
return "VolumeUp";
}
case 0x49: {
return "VolumeDown";
}
case 0x4a: {
return "Mute";
}
case 0x4f: {
return "F18";
}
case 0x50: {
return "F19";
}
case 0x5a: {
return "F20";
}
case 0x60: {
return "F5";
}
case 0x61: {
return "F6";
}
case 0x62: {
return "F7";
}
case 0x63: {
return "F3";
}
case 0x64: {
return "F8";
}
case 0x65: {
return "F9";
}
case 0x67: {
return "F11";
}
case 0x69: {
return "F13";
}
case 0x6a: {
return "F16";
}
case 0x6b: {
return "F14";
}
case 0x6d: {
return "F10";
}
case 0x6f: {
return "F12";
}
case 0x71: {
return "F15";
}
case 0x72: {
return "Help";
}
case 0x73: {
return "Home";
}
case 0x74: {
return "PageUp";
}
case 0x75: {
return "ForwardDelete";
}
case 0x76: {
return "F4";
}
case 0x77: {
return "End";
}
case 0x78: {
return "F2";
}
case 0x79: {
return "PageDown";
}
case 0x7a: {
return "F1";
}
case 0x7b: {
return "LeftArrow";
}
case 0x7c: {
return "RightArrow";
}
case 0x7d: {
return "DownArrow";
}
case 0x7e: {
return "UpArrow";
}
default: {
return "??";
}
}
}
function getModifiersForBitmask(bitMask, leftRight) {
console.log("modifier", bitMask);
if (bitMask === 0 || bitMask === -1) {
return "";
}
var modifierString = "";
if (leftRight && (bitMask & 0x00000001 || bitMask & 0x00002000)) {
if (bitMask & 0x00000001) {
modifierString += "⌃(L)";
}
if (bitMask & 0x00002000) {
modifierString += "⌃(R)";
}
} else {
if (bitMask & (1 << 18)) {
modifierString += "⌃";
}
}
if (leftRight && (bitMask & 0x00000002 || bitMask & 0x00000004)) {
if (bitMask & 0x00000002) {
modifierString += "⇧(L)";
}
if (bitMask & 0x00000004) {
modifierString += "⇧(R)";
}
} else {
if (bitMask & (1 << 17)) {
modifierString += "⇧";
}
}
if (leftRight && (bitMask & 0x00000010 || bitMask & 0x00000008)) {
if (bitMask & 0x00000010) {
modifierString += "⌘(R)";
}
if (bitMask & 0x00000008) {
modifierString += "⌘(L)";
}
} else {
if (bitMask & (1 << 20)) {
modifierString += "⌘";
}
}
if (leftRight && (bitMask & 0x00000020 || bitMask & 0x00000040)) {
if (bitMask & 0x00000020) {
modifierString += "⌥(L)";
}
if (bitMask & 0x00000040) {
modifierString += "⌥(R)";
}
} else {
if (bitMask & (1 << 19)) {
modifierString += "⌥";
}
}
if (bitMask & (1 << 23)) {
modifierString += "fn";
}
console.log("modifierstring", modifierString);
return modifierString;
}
function getShortcutString(value) {
var kCommand = 0x37;
var kShift = 0x38;
var kOption = 0x3a;
var kControl = 0x3b;
var kRightCommand = 0x36;
var kRightShift = 0x3c;
var kRightOption = 0x3d;
var kRightControl = 0x3e;
var kFunction = 0x3f;
var modsString = "";
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kFunction
) {
modsString = "fn " + modsString;
value = value.substring(3);
}
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kControl
) {
modsString += "⌃";
value = value.substring(3);
}
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kOption
) {
modsString += "⌥";
value = value.substring(3);
}
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kShift
) {
modsString += "⇧";
value = value.substring(3);
}
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kCommand
) {
modsString += "⌘";
value = value.substring(3);
}
if (value.length > 2 && value.substring(0, 2) === "aL") {
modsString = "l⌥ " + modsString;
value = value.substring(3);
}
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kRightOption
) {
modsString = "r⌥ " + modsString;
value = value.substring(3);
}
if (value.length > 2 && value.substring(0, 2) === "sL") {
modsString = "l⇧ " + modsString;
value = value.substring(3);
}
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kRightShift
) {
modsString = "l⇧ " + modsString;
value = value.substring(3);
}
if (value.length > 2 && value.substring(0, 2) === "cL") {
modsString = "l⌘ " + modsString;
value = value.substring(3);
}
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kRightCommand
) {
modsString = "r⌘ " + modsString;
value = value.substring(3);
}
if (value.length > 2 && value.substring(0, 2) === "rL") {
modsString = "l⌃ " + modsString;
value = value.substring(3);
}
if (
value.length > 2 &&
parseInt(value.substring(0, 2), 10) === kRightControl
) {
modsString = "r⌃ " + modsString;
value = value.substring(3);
}
return (
modsString + " " + getKeycodeStringForKeycode(parseInt(value, 10))
);
}
function getActionNameForID(aid, trigger) {
switch (aid) {
case -1: {
if (trigger.BTTTriggerType === 630) {
return "Open Group";
}
if (trigger.BTTShortcutToSend) {
return (
"Execute Keyboard Shortcut: " +
getShortcutString(trigger.BTTShortcutToSend)
);
}
return "No Action";
}
default:
return trigger.BTTPredefinedActionName;
}
}
function BTTInitialize() {}
function BTTWillCloseWindow() {}
function BTTWillHideWindow() {}
</script>
</head>
<body>
<div
id="triggerList"
style="
height: 100%;
display: flex;
flex-direction: column;
align-items: left;
justify-content: space-between;
"
></div>
</body>
</html>
If you get triggers via the get_triggers call they will also have a property BTTTriggerBelongsToPreset, so you could filter the list by preset. To filter by app you'd add the trigger_app_bundle_identifier filter ( Using Apple Script or JXA · GitBook (folivora.ai) )
It would also be easy to make the items clickable to trigger the action or you could make it always show the shortcuts for the active application.