diff --git a/README.md b/README.md index a81cfe9..b6f1fd7 100644 --- a/README.md +++ b/README.md @@ -312,7 +312,7 @@ Make `package.json` manually or by `$ npm init` in the directory. } ``` -Finally make `index.js` as below: +And make `index.js` as below: ```javascript module.exports = { @@ -324,7 +324,31 @@ module.exports = { Package must export one object. If the object has a function as a value of `preload` key, it will be called at page being loaded. -The function which receives two parameters `config` and `account`. +The function receives two parameters `config` and `account`. + +By defining `keymaps` key you can define plugin-defined key shortcut action. + +```javascript +module.exports = { + preload(config, account) { + console.log('Hello from plugin!', config, account); + }, + keymaps: { + 'alert-hello'(event, config, account) { + event.preventDefault(); + alert('Hello, ' + account.name); + } + } +}; +``` + +The object of `keymaps` has keymap action name (key) and its handler (value). Here 'alert-hello' +key shortcut action is defined. Key shortcut handler takes 3 arguments. `config` and `account` +is the same as `preload`'s. `event` is a `KeyboardEvent` browser event on the key shortcut +being called. You can cancel default event behavior by `.preventDefault()` method. + +User can specify the key shortcut as `plugin:{plugin name}:{action name}`. In above example, +`plugin:hello:alert-hello` is available in `keymaps` section in config.json. Note that you can use below APIs in the script. @@ -354,6 +378,8 @@ $ npm install mstdn-plugin-hello And then write what plugin should be loaded to `"plugins"` section of your account in `config.json`. `"hello"` should be added to the list. +If listed plugin defines some keymaps, you can specify it in `keymaps` section with +`plugin:{name}:{action}` format. ```json { @@ -368,12 +394,17 @@ And then write what plugin should be loaded to `"plugins"` section of your accou ] } ], + "keymaps": { + ... + + "ctrl+h": "plugin:hello:alert-hello" + }, ... } ``` -You can enable different plugin for each your accounts. +Note that you can enable different plugin for each your accounts. Finally open Mstdn.app and see DevTools via [Menu] -> [View] -> [Developper Tools] -> console. If window is too small to see DevTools, please make window size bigger. diff --git a/renderer/index.ts b/renderer/index.ts index 611aa72..79aaec6 100644 --- a/renderer/index.ts +++ b/renderer/index.ts @@ -6,6 +6,6 @@ import PluginsLoader from './plugins'; Ipc.on('mstdn:config', (c: Config, a: Account) => { const loader = new PluginsLoader(c, a); loader.loadAfterAppPrepared(); - setupKeymaps(c, a); + setupKeymaps(c, a, loader); document.title = `${document.title} @${a.name}@${a.host}`; }); diff --git a/renderer/key_handler.ts b/renderer/key_handler.ts index b8c31fd..d64176b 100644 --- a/renderer/key_handler.ts +++ b/renderer/key_handler.ts @@ -3,6 +3,7 @@ import {remote} from 'electron'; import * as Mousetrap from 'mousetrap'; import * as Ipc from './ipc'; import log from './log'; +import PluginsLoader from './plugins'; import {Config, Account} from '../main/config'; function scrollable() { @@ -58,6 +59,7 @@ const ShortcutActions = { export default function setupKeymaps( config: Config, account: Account, + loader: PluginsLoader, ) { const dataDir = config.__DATA_DIR || '/'; for (const key in config.keymaps) { @@ -85,6 +87,16 @@ export default function setupKeymaps( log.error('Failed to run shortcut script ' + script, e); } }); + } else if (action.startsWith('plugin:')) { + // Format is 'plugin:{name}:{action}' + const split = action.split(':').slice(1); + if (split.length <= 1) { + log.error('Invalid format keymap. Plugin-defined action should be "plugin:{name}:{action}":', action); + continue; + } + Mousetrap.bind(key, e => { + loader.runKeyShortcut(e, split[0], split[1]); + }); } else if (action.startsWith('/')) { Mousetrap.bind(key, e => { e.preventDefault(); diff --git a/renderer/plugins.ts b/renderer/plugins.ts index e5ac8a9..0b08ea0 100644 --- a/renderer/plugins.ts +++ b/renderer/plugins.ts @@ -3,7 +3,10 @@ import {Config, Account} from '../main/config'; import log from './log'; interface Plugin { - preload(c: Config, a: Account): void; + preload?(c: Config, a: Account): void; + keymaps?: { + [action: string]: (e: KeyboardEvent, c: Config, a: Account) => void; + }; } interface Plugins { [module_path: string]: Plugin; @@ -83,4 +86,34 @@ export default class PluginsLoader { log.info('Plugins were loaded:', this.preloads); return true; } + + findPluginByName(name: string): Plugin | null { + const pluginName = `mstdn-plugin-${name}`; + for (const p in this.preloads) { + if (p.endsWith(pluginName)) { + return this.preloads[p]; + } + } + return null; + } + + runKeyShortcut(event: KeyboardEvent, name: string, action: string) { + const plugin = this.findPluginByName(name); + if (plugin === null) { + log.error(`While trying to execute key shortcut '${action}', plugin for '${name}' not found:`, this.preloads); + return; + } + + const f = (plugin.keymaps || {})[action]; + if (!f) { + log.error(`There is no key shortcut action '${action}' in plugin '${name}'`, plugin); + return; + } + + try { + f(event, this.config, this.account); + } catch (e) { + log.error(`Error while executing plugin-defined key short action: ${action} with plugin '${name}'`, e); + } + } }