### Bash: Installing tbkeys from XPI Source: https://context7.com/wshanks/tbkeys/llms.txt Provides instructions for downloading and installing the tbkeys add-on from a GitHub release using curl and the Thunderbird Add-ons Manager. The extension automatically updates from GitHub releases. ```bash # Download and install from GitHub releases curl -LO https://github.com/wshanks/tbkeys/releases/latest/download/tbkeys.xpi # Open Thunderbird Add-ons Manager (Tools -> Add-ons) # Click gear icon -> "Install Add-on From File..." -> select tbkeys.xpi # Extension auto-updates from GitHub releases page ``` -------------------------------- ### JSON: Custom Configuration Example for tbkeys Source: https://context7.com/wshanks/tbkeys/llms.txt An example JSON configuration file demonstrating how to map keyboard shortcuts to various commands in tbkeys. This includes commands for message navigation, opening messages, deletion, reply, archive, new messages, closing tabs, and scrolling. ```json { "j": "cmd:cmd_nextMsg", "k": "cmd:cmd_previousMsg", "o": "cmd:cmd_openMessage", "f": "cmd:cmd_forward", "#": "cmd:cmd_delete", "r": "cmd:cmd_reply", "a": "cmd:cmd_replyall", "x": "cmd:cmd_archive", "c": "func:MsgNewMessage", "u": "tbkeys:closeMessageAndRefresh", "g i": "func:goDoCommand('cmd_goFolder')", "g t": "window.document.getElementById('tabmail-tabs').advanceSelectedTab(1, true)", "g T": "window.document.getElementById('tabmail-tabs').advanceSelectedTab(-1, true)", "ctrl+j": "window.document.getElementById('threadTree').scrollByLines(1)", "ctrl+k": "window.document.getElementById('threadTree').scrollByLines(-1)", "space": "window.gTabmail.currentAboutMessage.getMessagePaneBrowser().contentWindow.scrollBy(0, 100)", "shift+space": "window.gTabmail.currentAboutMessage.getMessagePaneBrowser().contentWindow.scrollBy(0, -100)" } ``` -------------------------------- ### Subscribe to Feed Source: https://github.com/wshanks/tbkeys/blob/main/README.md Opens the dialog to subscribe to a feed, typically requiring a selected folder. ```javascript window.openSubscriptionsDialog(window.GetSelectedMsgFolders()[0]) ``` -------------------------------- ### Command Types Source: https://context7.com/wshanks/tbkeys/llms.txt Explains the different types of commands that can be bound to keyboard shortcuts within the tbkeys extension. ```APIDOC ## Command Types ### Simple Commands (cmd:) Execute native Thunderbird commands using `goDoCommand()`. Commands can be found in Thunderbird's mainCommandSet.inc.xhtml. ### Simple Function Calls (func:) Call functions defined on the Thunderbird window object without arguments. ### Built-in Custom Functions (tbkeys:) Execute custom functions provided by tbkeys. Currently only `closeMessageAndRefresh` is available. ### MailExtension Messages (memsg:) Send messages to other MailExtensions using their extension ID. ``` -------------------------------- ### Robust Settings Retrieval with Retry Logic (JavaScript) Source: https://context7.com/wshanks/tbkeys/llms.txt Retrieves settings from `browser.storage.local` with a built-in retry mechanism to handle potential storage access issues. It includes a promise-based timeout for operations and migrates old 'keys' settings to 'mainkeys', applying default values if settings are missing. This function is crucial for ensuring settings are loaded reliably. ```javascript // From background.js - robust settings retrieval const promiseWithTimeout = function (ms, promise) { let timeout = new Promise((resolve, reject) => { let id = setTimeout(() => { clearTimeout(id); reject(new Error("Timed out in " + ms + "ms.")); }, ms); }); return Promise.race([promise, timeout]); }; async function getSettings() { let settings; const retries = 7; const baseTimeout = 700; for (let tryNum = 0; ; tryNum++) { try { settings = await promiseWithTimeout( baseTimeout * (tryNum + 1), browser.storage.local.get() ); break; } catch (error) { if (tryNum >= retries) { error.message = "TBKeys: could not load settings -- " + error.message; throw error; } } } // Migrate old "keys" setting to "mainkeys" if (settings.hasOwnProperty("keys")) { settings.mainkeys = settings.keys; await browser.storage.local.remove("keys"); await browser.storage.local.set({ mainkeys: settings.mainkeys }); } // Apply defaults for missing settings let defaults = { mainkeys: '{"j": "cmd:cmd_nextMsg", "k": "cmd:cmd_previousMsg"}', composekeys: "{}" }; for (let setting of Object.keys(defaults)) { if (!settings.hasOwnProperty(setting)) { settings[setting] = defaults[setting]; } } return settings; } // Usage let settings = await getSettings(); await browser.tbkeys.bindKeys({ main: JSON.parse(settings.mainkeys), compose: JSON.parse(settings.composekeys) }); ``` -------------------------------- ### Execute Thunderbird Commands Source: https://github.com/wshanks/tbkeys/blob/main/README.md Executes built-in Thunderbird commands using the `goDoCommand()` function. Command names can be found in the Thunderbird source code. ```javascript window.goDoCommand('cmd_newFolder') ``` -------------------------------- ### Thunderbird Native Commands (JSON) Source: https://context7.com/wshanks/tbkeys/llms.txt Defines simple commands that execute native Thunderbird actions using `goDoCommand()`. These commands are part of Thunderbird's mainCommandSet and are triggered by specific keybindings. ```json { "r": "cmd:cmd_reply", // Reply to selected message "#": "cmd:cmd_delete", // Delete selected message "x": "cmd:cmd_archive", // Archive selected message "j": "cmd:cmd_nextMsg", // Navigate to next message "k": "cmd:cmd_previousMsg", // Navigate to previous message "o": "cmd:cmd_openMessage", // Open message in new tab "f": "cmd:cmd_forward", // Forward message "a": "cmd:cmd_replyall", // Reply all "ctrl+n": "cmd:cmd_newFolder" // Create new folder } ``` -------------------------------- ### Thunderbird Simple Function Calls (JSON) Source: https://context7.com/wshanks/tbkeys/llms.txt Maps keybindings to simple function calls that are executed directly on the Thunderbird window object. These functions are invoked without any arguments. ```json { "c": "func:MsgNewMessage", // Compose new message "t": "func:CloseTabOrWindow", // Close current tab "g f": "func:goDoCommand", // Go to folder dialog "ctrl+tab": "func:SwitchToNextTab", // Next tab "ctrl+shift+tab": "func:SwitchToPreviousTab" // Previous tab } ``` -------------------------------- ### JavaScript: Building Key Commands for Mousetrap Source: https://context7.com/wshanks/tbkeys/llms.txt Defines a function to parse and convert command strings into executable callback functions for Mousetrap. It supports various command types like 'cmd', 'func', 'tbkeys', 'memsg', and arbitrary JavaScript evaluation. Dependencies: Mousetrap, Services.obs, builtins. Inputs: window object, command string. Outputs: callback function. ```javascript // From implementation.js function buildKeyCommand(win, command) { let callback = function () { let window = win; // Available for eval commands let cmdType = command.split(":", 1)[0]; let cmdBody = command.slice(cmdType.length + 1); switch (cmdType) { case "cmd": win.goDoCommand(cmdBody); break; case "func": win[cmdBody](); break; case "tbkeys": builtins[cmdBody](win); break; case "memsg": Services.obs.notifyObservers(null, "tbkeys-memsg", cmdBody); break; case "unset": break; default: eval(command); // Arbitrary JavaScript break; } return false; }; return callback; } // Usage in bindKeysInWindow function bindKeysInWindow(win, keys) { win.Mousetrap.reset(); for (let [key, command] of Object.entries(keys)) { win.Mousetrap.bind(key, buildKeyCommand(win, command)); } } // Example: // bindKeysInWindow(window, {"j": "cmd:cmd_nextMsg", "k": "cmd:cmd_previousMsg"}) // Creates callbacks for "j" and "k" that execute goDoCommand with appropriate commands ``` -------------------------------- ### Custom tbkeys Function Calls Source: https://github.com/wshanks/tbkeys/blob/main/README.md Calls custom functions defined within the tbkeys add-on. Currently supports `closeMessageAndRefresh` which closes the current tab if it's not the first and refreshes all accounts. ```javascript tbkeys:closeMessageAndRefresh ``` -------------------------------- ### tbkeys.bindKeys API Source: https://context7.com/wshanks/tbkeys/llms.txt Binds custom keyboard shortcuts to Thunderbird commands or custom functions. This API can be called from the background script to apply or update keybindings. ```APIDOC ## POST /tbkeys/bindKeys ### Description Binds keyboard shortcuts to commands across all Thunderbird windows. This API function is called from the background script whenever keybindings need to be applied or updated. ### Method POST ### Endpoint /tbkeys/bindKeys ### Parameters #### Request Body - **main** (object) - Optional - Keybindings for the main Thunderbird window. - **key** (string) - Required - The keyboard shortcut (e.g., "j", "ctrl+enter"). - **command** (string) - Required - The command to execute (e.g., "cmd:cmd_nextMsg", "func:MsgNewMessage"). - **compose** (object) - Optional - Keybindings for the compose window. - **key** (string) - Required - The keyboard shortcut. - **command** (string) - Required - The command to execute. ### Request Example ```json { "main": { "j": "cmd:cmd_nextMsg", "k": "cmd:cmd_previousMsg", "u": "tbkeys:closeMessageAndRefresh" }, "compose": { "ctrl+enter": "cmd:cmd_sendLater" } } ``` ### Response #### Success Response (200) - **status** (string) - Indicates success ('ok') or failure ('error'). #### Response Example ```json { "status": "ok" } ``` ``` -------------------------------- ### Execute Arbitrary JavaScript (Eval Commands) Source: https://github.com/wshanks/tbkeys/blob/main/README.md Eval commands allow execution of arbitrary JavaScript code when a key binding is triggered. Any command not matching other prefixes is treated as an eval command. Note: Eval commands are not available in tbkeys-lite. ```javascript window.document.getElementById('tabmail-tabs').advanceSelectedTab(1, true) ``` ```javascript window.document.getElementById('tabmail-tabs').advanceSelectedTab(-1, true) ``` ```javascript window.document.getElementById('threadTree').scrollByLines(1) ``` ```javascript window.document.getElementById('threadTree').scrollByLines(-1) ``` -------------------------------- ### tbkeys.onSendMessage API Source: https://context7.com/wshanks/tbkeys/llms.txt An event listener that triggers when a keybinding with the `memsg:` prefix is executed. It allows tbkeys to send messages to other MailExtensions. ```APIDOC ## POST /tbkeys/onSendMessage/addListener ### Description Listens for messages sent from tbkeys when a `memsg:` keybinding is triggered. This allows communication with other MailExtensions. ### Method POST ### Endpoint /tbkeys/onSendMessage/addListener ### Parameters #### Request Body - **callback** (function) - Required - A callback function that receives the target extension ID and the message payload. - **extensionID** (string) - The ID of the target MailExtension. - **message** (string) - The message payload to send. ### Request Example ```javascript browser.tbkeys.onSendMessage.addListener(async (extensionID, message) => { browser.runtime.sendMessage(extensionID, message); }); ``` ### Response #### Success Response (200) - **status** (string) - Indicates success ('ok'). #### Response Example ```json { "status": "ok" } ``` ``` -------------------------------- ### Execute Arbitrary JavaScript Commands in Thunderbird Source: https://context7.com/wshanks/tbkeys/llms.txt Allows execution of arbitrary JavaScript code within the Thunderbird window context. Any command not matching specific prefixes is treated as an 'eval' command. This enables advanced customizations like navigating tabs, scrolling messages, and subscribing to feeds. Note: 'eval' commands are not available in the 'tbkeys-lite' version. ```javascript { // Navigate tabs "gt": "window.document.getElementById('tabmail-tabs').advanceSelectedTab(1, true)", "gT": "window.document.getElementById('tabmail-tabs').advanceSelectedTab(-1, true)", // Scroll message list "shift+j": "window.document.getElementById('threadTree').scrollByLines(5)", "shift+k": "window.document.getElementById('threadTree').scrollByLines(-5)", // Scroll message body (Thunderbird 115+) "space": "window.gTabmail.currentAboutMessage.getMessagePaneBrowser().contentWindow.scrollBy(0, 100)", "shift+space": "window.gTabmail.currentAboutMessage.getMessagePaneBrowser().contentWindow.scrollBy(0, -100)", // Subscribe to feed "s": "window.openSubscriptionsDialog(window.GetSelectedMsgFolders()[0])", // Multiple commands "d": "window.goDoCommand('cmd_delete'); window.goDoCommand('cmd_nextMsg')" } // Note: eval commands are not available in tbkeys-lite ``` -------------------------------- ### Saving Thunderbird Settings with JSON Validation (JavaScript) Source: https://context7.com/wshanks/tbkeys/llms.txt Saves user preferences to `browser.storage.local` after validating that the `mainkeys` and `composekeys` fields contain valid JSON. If the JSON is invalid, an alert is shown to the user. After successful saving, it re-applies the keybindings by calling `applyKeys` in the background script. It also includes a function to unset single keys that might conflict with default shortcuts. ```javascript // From options.js async function saveOptions(e) { e.preventDefault(); // Validate JSON syntax let mainkeysField = document.querySelector("#mainkeys"); let composekeysField = document.querySelector("#composekeys"); try { JSON.parse(mainkeysField.value); JSON.parse(composekeysField.value); } catch (error) { alert("Invalid JSON format"); return; } // Save to storage await browser.storage.local.set({ mainkeys: mainkeysField.value, composekeys: composekeysField.value }); // Reapply keybindings let background = browser.extension.getBackgroundPage(); await background.applyKeys(); } // Unset single keys that conflict with default shortcuts async function unsetSingleKeys() { let settings = await browser.storage.local.get("mainkeys"); let keys = JSON.parse(settings.mainkeys || "{}"); let singles = ["a", "c", "f", "j", "k", "m", "o", "p", "r", "s", "t", "u", "w", "x", "#", "]", "["]; for (let key of singles) { if (!keys.hasOwnProperty(key)) { keys[key] = "unset"; } } await browser.storage.local.set({ mainkeys: JSON.stringify(keys, null, 4) }); } ``` -------------------------------- ### Call Thunderbird Window Functions Source: https://github.com/wshanks/tbkeys/blob/main/README.md Calls functions defined on the Thunderbird window object without any arguments. This is used for actions like closing tabs. ```javascript func:CloseTabOrWindow ``` -------------------------------- ### Forward MailExtension Messages (JavaScript) Source: https://context7.com/wshanks/tbkeys/llms.txt Listens for keybindings prefixed with 'memsg:' and forwards the associated message to a specified MailExtension. This allows tbkeys to communicate with other add-ons. The listener receives the target extension ID and the message payload. ```javascript // In background.js - forward messages from tbkeys to other extensions browser.tbkeys.onSendMessage.addListener(async (extensionID, message) => { // extensionID: string - target extension ID // message: string - message payload to send browser.runtime.sendMessage(extensionID, message); }); // Example keybinding that triggers this: // "m": "memsg:myextension@example.com:markAsImportant" // When "m" is pressed, onSendMessage fires with: // extensionID = "myextension@example.com" // message = "markAsImportant" ``` -------------------------------- ### Send MailExtension Messages Source: https://github.com/wshanks/tbkeys/blob/main/README.md Sends messages to specific Thunderbird extensions using the `browser.runtime.sendMessage()` API. Currently supports string messages only. ```javascript memsg:: ``` -------------------------------- ### Bind Keyboard Shortcuts in Thunderbird (JavaScript) Source: https://context7.com/wshanks/tbkeys/llms.txt Applies custom keyboard shortcuts to Thunderbird commands for both the main window and compose window. This function is typically called from the background script to load keybindings from storage. It utilizes Mousetrap syntax for defining key combinations and commands. ```javascript await browser.tbkeys.bindKeys({ main: { "j": "cmd:cmd_nextMsg", "k": "cmd:cmd_previousMsg", "o": "cmd:cmd_openMessage", "f": "cmd:cmd_forward", "#": "cmd:cmd_delete", "r": "cmd:cmd_reply", "a": "cmd:cmd_replyall", "x": "cmd:cmd_archive", "c": "func:MsgNewMessage", "u": "tbkeys:closeMessageAndRefresh", "ctrl+j ctrl+k": "func:CloseTabOrWindow", "g i": "func:goDoCommand('cmd_goFolder')" }, compose: { "ctrl+enter": "cmd:cmd_sendLater", "ctrl+shift+enter": "cmd:cmd_sendNow" } }); // Keybindings are now active in all open and future Thunderbird windows ``` -------------------------------- ### Send MailExtension Messages (JSON) Source: https://context7.com/wshanks/tbkeys/llms.txt Configures keybindings to send messages to other MailExtensions, identified by their extension ID. This enables inter-add-on communication within Thunderbird. ```json // Keybinding configuration { "m i": "memsg:myextension@example.com:markImportant", "m u": "memsg:myextension@example.com:markUnread", "s": "memsg:spam-filter@example.com:markAsSpam" } // In the target extension (myextension@example.com) browser.runtime.onMessage.addListener((message, sender) => { if (sender.id === "tbkeys@addons.thunderbird.net") { if (message === "markImportant") { // Handle mark as important } else if (message === "markUnread") { // Handle mark as unread } } }); ``` -------------------------------- ### tbkeys Built-in Custom Functions (JSON) Source: https://context7.com/wshanks/tbkeys/llms.txt Utilizes custom functions provided by the tbkeys extension itself. Currently, only `closeMessageAndRefresh` is supported, which closes the current message tab, refreshes mail accounts, and expands all threads. ```json { "u": "tbkeys:closeMessageAndRefresh" } // When triggered: // 1. Closes current tab if it's not the first tab // 2. Refreshes all mail accounts // 3. Expands all threads // Mimics Gmail's "u" keybinding behavior ``` -------------------------------- ### Unset Key Bindings Source: https://github.com/wshanks/tbkeys/blob/main/README.md Sets a key binding to 'unset', meaning no action will be performed when triggered. Useful for disabling default Thunderbird key bindings. ```plaintext unset ``` -------------------------------- ### Scroll Message Body (Version Specific) Source: https://github.com/wshanks/tbkeys/blob/main/README.md Scrolls the message body content either down or up, with different implementations for Thunderbird versions 115+ and 102. ```javascript window.gTabmail.currentAboutMessage.getMessagePaneBrowser().contentWindow.scrollBy(0, 100) ``` ```javascript window.document.getElementById('messagepane').contentDocument.documentElement.getElementsByTagName('body')[0].scrollBy(0, 100) ``` ```javascript window.gTabmail.currentAboutMessage.getMessagePaneBrowser().contentWindow.scrollBy(0, -100) ``` ```javascript window.document.getElementById('messagepane').contentDocument.documentElement.getElementsByTagName('body')[0].scrollBy(0, -100) ``` -------------------------------- ### JavaScript: Custom Mousetrap Stop Callback Source: https://context7.com/wshanks/tbkeys/llms.txt Implements a custom stop callback function for Mousetrap to prevent keybindings from triggering in text input fields unless modifiers are used. It checks for various text input element types and contentEditable attributes. Dependencies: Mousetrap library. Inputs: event object, element, combo string, sequence string. Outputs: boolean indicating whether to stop the keybinding. ```javascript // From implementation.js function stopCallback(e, element, combo, seq) { let tagName = element.tagName.toLowerCase(); // Check if element is a text input field let isText = tagName == "imconversation" || tagName == "textbox" || tagName == "input" || tagName == "select" || tagName == "textarea" || tagName == "html:input" || tagName == "search-textbox" || tagName == "html:textarea" || tagName == "browser" || tagName == "global-search-bar" || tagName == "search-bar" || tagName == "moz-input-search" || (element.contentEditable && element.contentEditable == "true"); // Check for inherited contentEditable if (!isText && element.contentEditable == "inherit") { let ancestor = element; while (ancestor.contentEditable == "inherit") { ancestor = ancestor.parentElement; if (ancestor === null) { if (element.ownerDocument.designMode == "on") { isText = true; } break; } if (ancestor.contentEditable == "true") { isText = true; break; } } } // Extract first combo from sequence (e.g., "ctrl+j" from "ctrl+j ctrl+k") let firstCombo = combo; if (seq !== undefined) { firstCombo = seq.trim().split(" ")[0]; } // Check if first combo has modifiers (ctrl, alt, meta, option, command) let modifiers = ["ctrl", "alt", "meta", "option", "command"]; let hasModifier = false; for (let mod of modifiers) { if (firstCombo.includes(mod)) { hasModifier = true; break; } } // Stop if in text field and no modifiers return isText && !hasModifier; } // Example behavior: // "j" pressed in email body -> stopCallback returns true, keybinding ignored // "ctrl+j" pressed in email body -> stopCallback returns false, keybinding fires // "j" pressed on folder list -> stopCallback returns false, keybinding fires ``` -------------------------------- ### Unset Thunderbird Keybindings Source: https://context7.com/wshanks/tbkeys/llms.txt Disables default Thunderbird keybindings to prevent accidental triggering. This is useful for remapping common shortcuts without conflicts. The configuration is provided as a JSON object where keys represent the shortcut and the value 'unset' deactivates it. ```javascript { "f": "unset", // Disables forward shortcut "r": "unset", // Disables reply shortcut "delete": "unset", // Disables delete key "backspace": "unset" // Disables backspace for delete } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.