From a507dd0dbe94e91f77dd5323b9c48fcc88eac576 Mon Sep 17 00:00:00 2001 From: asmagill Date: Tue, 20 Jun 2023 01:15:40 +0100 Subject: [PATCH 01/55] Add LeftRightHotkey spoon --- Source/LeftRightHotkey.spoon/docs.json | 401 +++++++++++++++++++ Source/LeftRightHotkey.spoon/init.lua | 515 +++++++++++++++++++++++++ 2 files changed, 916 insertions(+) create mode 100644 Source/LeftRightHotkey.spoon/docs.json create mode 100644 Source/LeftRightHotkey.spoon/init.lua diff --git a/Source/LeftRightHotkey.spoon/docs.json b/Source/LeftRightHotkey.spoon/docs.json new file mode 100644 index 00000000..f283dfe4 --- /dev/null +++ b/Source/LeftRightHotkey.spoon/docs.json @@ -0,0 +1,401 @@ +[ + { + "Constant" : [ + + ], + "submodules" : [ + + ], + "Function" : [ + + ], + "Variable" : [ + + ], + "stripped_doc" : [ + + ], + "desc" : "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.", + "type" : "Module", + "Deprecated" : [ + + ], + "Constructor" : [ + + ], + "Field" : [ + + ], + "items" : [ + { + "desc" : "Create and enable a new hotkey with the specified left\/right specific modifiers.", + "def" : "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc" : [ + "Create and enable a new hotkey with the specified left\/right specific modifiers.", + "" + ], + "doc" : "Create and enable a new hotkey with the specified left\/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left\/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", + "notes" : [ + " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." + ], + "signature" : "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "type" : "Method", + "returns" : [ + " * a new enabled hotkey with the specified left\/right modifiers.", + "" + ], + "name" : "bind", + "parameters" : [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", + " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", + " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", + " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", + " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", + " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", + " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", + " * \"lShift\" or \"l⇧\" for the left Shift modifier", + " * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil", + "" + ] + }, + { + "desc" : "Deletes all previously set callbacks for a given keyboard combination", + "def" : "LeftRightHotkey:deleteAll(mods, key)", + "stripped_doc" : [ + "Deletes all previously set callbacks for a given keyboard combination", + "" + ], + "doc" : "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "notes" : [ + + ], + "signature" : "LeftRightHotkey:deleteAll(mods, key)", + "type" : "Method", + "returns" : [ + " * None" + ], + "name" : "deleteAll", + "parameters" : [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", + " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", + " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", + " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", + " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", + " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", + " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", + " * \"lShift\" or \"l⇧\" for the left Shift modifier", + " * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + "" + ] + }, + { + "desc" : "Disables all previously set callbacks for a given keyboard combination", + "def" : "LeftRightHotkey:disableAll(mods, key)", + "stripped_doc" : [ + "Disables all previously set callbacks for a given keyboard combination", + "" + ], + "doc" : "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "notes" : [ + + ], + "signature" : "LeftRightHotkey:disableAll(mods, key)", + "type" : "Method", + "returns" : [ + " * None" + ], + "name" : "disableAll", + "parameters" : [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", + " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", + " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", + " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", + " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", + " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", + " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", + " * \"lShift\" or \"l⇧\" for the left Shift modifier", + " * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + "" + ] + }, + { + "desc" : "Create a new hotkey with the specified left\/right specific modifiers.", + "def" : "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc" : [ + "Create a new hotkey with the specified left\/right specific modifiers.", + "" + ], + "doc" : "Create a new hotkey with the specified left\/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left\/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", + "notes" : [ + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." + ], + "signature" : "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "type" : "Method", + "returns" : [ + " * a new, initially disabled, hotkey with the specified left\/right modifiers.", + "" + ], + "name" : "new", + "parameters" : [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", + " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", + " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", + " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", + " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", + " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", + " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", + " * \"lShift\" or \"l⇧\" for the left Shift modifier", + " * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil", + "" + ] + }, + { + "desc" : "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "def" : "LeftRightHotkey:start() -> self", + "stripped_doc" : [ + "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "" + ], + "doc" : "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", + "notes" : [ + " * this enables the use of hotkeys created by using this Spoon." + ], + "signature" : "LeftRightHotkey:start() -> self", + "type" : "Method", + "returns" : [ + " * the LeftRightHotkey spoon object", + "" + ], + "name" : "start", + "parameters" : [ + " * None", + "" + ] + }, + { + "desc" : "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "def" : "LeftRightHotkey:stop() -> self", + "stripped_doc" : [ + "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "" + ], + "doc" : "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", + "notes" : [ + " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." + ], + "signature" : "LeftRightHotkey:stop() -> self", + "type" : "Method", + "returns" : [ + " * the LeftRightHotkey spoon object", + "" + ], + "name" : "stop", + "parameters" : [ + " * None", + "" + ] + } + ], + "Command" : [ + + ], + "doc" : "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.\n\nThis is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon.\n\nThe `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents:\n\n * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey.\n * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey.\n * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey.\n * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)\n\nThe following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n\nThe modifiers table for any given hotkey is all inclusive; this means that if you specify `{ \"rShift\", \"lShift\" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either\/or, then stick with [hs.hotkey](hs.hotkey.html).\n\nAlternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon:\n e.g. `LeftRightHotkey:bind({ \"rCmd\", \"rShift\" }, \"a\", myFunction)` *and* `LeftRightHotkey:bind({ \"lCmd\", \"rShift\" }, \"a\", myFunction)`\n\nThis spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:\n * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.\n * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.\n * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary.\n * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled\/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.\n\nLike all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher.\n\nDownload: [https:\/\/github.com\/Hammerspoon\/Spoons\/raw\/master\/Spoons\/LeftRightHotkey.spoon.zip](https:\/\/github.com\/Hammerspoon\/Spoons\/raw\/master\/Spoons\/LeftRightHotkey.spoon.zip)", + "Method" : [ + { + "desc" : "Create a new hotkey with the specified left\/right specific modifiers.", + "def" : "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc" : [ + "Create a new hotkey with the specified left\/right specific modifiers.", + "" + ], + "doc" : "Create a new hotkey with the specified left\/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left\/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", + "notes" : [ + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." + ], + "signature" : "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "type" : "Method", + "returns" : [ + " * a new, initially disabled, hotkey with the specified left\/right modifiers.", + "" + ], + "name" : "new", + "parameters" : [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", + " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", + " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", + " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", + " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", + " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", + " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", + " * \"lShift\" or \"l⇧\" for the left Shift modifier", + " * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil", + "" + ] + }, + { + "desc" : "Deletes all previously set callbacks for a given keyboard combination", + "def" : "LeftRightHotkey:deleteAll(mods, key)", + "stripped_doc" : [ + "Deletes all previously set callbacks for a given keyboard combination", + "" + ], + "doc" : "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "notes" : [ + + ], + "signature" : "LeftRightHotkey:deleteAll(mods, key)", + "type" : "Method", + "returns" : [ + " * None" + ], + "name" : "deleteAll", + "parameters" : [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", + " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", + " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", + " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", + " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", + " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", + " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", + " * \"lShift\" or \"l⇧\" for the left Shift modifier", + " * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + "" + ] + }, + { + "desc" : "Disables all previously set callbacks for a given keyboard combination", + "def" : "LeftRightHotkey:disableAll(mods, key)", + "stripped_doc" : [ + "Disables all previously set callbacks for a given keyboard combination", + "" + ], + "doc" : "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "notes" : [ + + ], + "signature" : "LeftRightHotkey:disableAll(mods, key)", + "type" : "Method", + "returns" : [ + " * None" + ], + "name" : "disableAll", + "parameters" : [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", + " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", + " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", + " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", + " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", + " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", + " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", + " * \"lShift\" or \"l⇧\" for the left Shift modifier", + " * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + "" + ] + }, + { + "desc" : "Create and enable a new hotkey with the specified left\/right specific modifiers.", + "def" : "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc" : [ + "Create and enable a new hotkey with the specified left\/right specific modifiers.", + "" + ], + "doc" : "Create and enable a new hotkey with the specified left\/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left\/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", + "notes" : [ + " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." + ], + "signature" : "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "type" : "Method", + "returns" : [ + " * a new enabled hotkey with the specified left\/right modifiers.", + "" + ], + "name" : "bind", + "parameters" : [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", + " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", + " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", + " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", + " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", + " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", + " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", + " * \"lShift\" or \"l⇧\" for the left Shift modifier", + " * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil", + "" + ] + }, + { + "desc" : "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "def" : "LeftRightHotkey:start() -> self", + "stripped_doc" : [ + "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "" + ], + "doc" : "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", + "notes" : [ + " * this enables the use of hotkeys created by using this Spoon." + ], + "signature" : "LeftRightHotkey:start() -> self", + "type" : "Method", + "returns" : [ + " * the LeftRightHotkey spoon object", + "" + ], + "name" : "start", + "parameters" : [ + " * None", + "" + ] + }, + { + "desc" : "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "def" : "LeftRightHotkey:stop() -> self", + "stripped_doc" : [ + "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "" + ], + "doc" : "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", + "notes" : [ + " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." + ], + "signature" : "LeftRightHotkey:stop() -> self", + "type" : "Method", + "returns" : [ + " * the LeftRightHotkey spoon object", + "" + ], + "name" : "stop", + "parameters" : [ + " * None", + "" + ] + } + ], + "name" : "LeftRightHotkey" + } +] diff --git a/Source/LeftRightHotkey.spoon/init.lua b/Source/LeftRightHotkey.spoon/init.lua new file mode 100644 index 00000000..e1a55dd5 --- /dev/null +++ b/Source/LeftRightHotkey.spoon/init.lua @@ -0,0 +1,515 @@ +--- === LeftRightHotkey === +--- +--- This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free. +--- +--- This is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon. +--- +--- The `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents: +--- +--- * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey. +--- * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey. +--- * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey. +--- * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false) +--- +--- The following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon: +--- * "lCmd", "lCommand", or "l⌘" for the left Command modifier +--- * "rCmd", "rCommand", or "r⌘" for the right Command modifier +--- * "lCtrl", "lControl" or "l⌃" for the left Control modifier +--- * "rCtrl", "rControl" or "r⌃" for the right Control modifier +--- * "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier +--- * "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier +--- * "lShift" or "l⇧" for the left Shift modifier +--- * "rShift" or "r⇧" for the right Shift modifier +--- +--- The modifiers table for any given hotkey is all inclusive; this means that if you specify `{ "rShift", "lShift" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either/or, then stick with [hs.hotkey](hs.hotkey.html). +--- +--- Alternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon: +--- e.g. `LeftRightHotkey:bind({ "rCmd", "rShift" }, "a", myFunction)` *and* `LeftRightHotkey:bind({ "lCmd", "rShift" }, "a", myFunction)` +--- +--- This spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following: +--- * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely. +--- * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed. +--- * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary. +--- * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above. +--- +--- Like all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher. +--- +--- Download: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip) + +local spoons = require("hs.spoons") +local log = require("hs.logger").new("LeftRightHotkey", require("hs.settings").get("LeftRightHotkey_logLevel") or "warning") + +local fnutils = require("hs.fnutils") +local hotkey = require("hs.hotkey") +local keycodes = require("hs.keycodes") +local timer = require("hs.timer") +local eventtap = require("hs.eventtap") +local etevent = eventtap.event + +local obj = { +-- Metadata + name = "LeftRightHotkey", + author = "A-Ron", + homepage = "https://github.com/Hammerspoon/Spoons", + license = "MIT - https://opensource.org/licenses/MIT", + spoonPath = spoons.scriptPath(), +} +-- version is outside of obj table definition to facilitate its auto detection by +-- external documentation generation scripts +obj.version = "0.1" + +-- defines the keys to display in object's __tostring metamethod; define here so subsequent +-- additions are not included in the output +local metadataKeys = {} ; for k, v in fnutils.sortByKeys(obj) do table.insert(metadataKeys, k) end + +obj.__index = obj + +---------- Local Functions And Variables ---------- + +local modiferBase = { + ["lcmd"] = "cmd", + ["rcmd"] = "cmd", + ["lshift"] = "shift", + ["rshift"] = "shift", + ["lalt"] = "alt", + ["ralt"] = "alt", + ["lctrl"] = "ctrl", + ["rctrl"] = "ctrl", +} + +local altMods = { + ["⇧"] = "shift", + ["opt"] = "alt", + ["option"] = "alt", + ["⌥"] = "alt", + ["⌘"] = "cmd", + ["command"] = "cmd", + ["⌃"] = "ctrl", + ["control"] = "ctrl", +} + +local modifierMasks = { + lcmd = 1 << 0, + rcmd = 1 << 1, + lshift = 1 << 2, + rshift = 1 << 3, + lalt = 1 << 4, + ralt = 1 << 5, + lctrl = 1 << 6, + rctrl = 1 << 7, +} + +local existantHotKeys = {} + +local queuedHotKeys = {} +for i = 1, (1 << 8) - 1, 1 do queuedHotKeys[i] = setmetatable({}, { __mode = "k" }) end + +-- copies flag tables so that if the user wants to reuse his tables, we don't +-- modify them +local shallowCopyTable = function(tbl) + local newTbl = {} + local key, value = next(tbl) + while key do + newTbl[key] = value + key, value = next(tbl, key) + end + return newTbl +end + +-- use lookup tables above to convert all flags to one format to simplify later checks +local normalizeModsTable = function(tbl) + local newTbl = shallowCopyTable(tbl) + for i, m in ipairs(newTbl) do + local mod = m:lower() + for k, v in pairs(altMods) do + local s, e = mod:find(k .. "$") + if s then + newTbl[i] = mod:sub(1, s - 1) .. v + break + end + end + newTbl[i] = newTbl[i]:lower() + end + return newTbl +end + +-- converts our modifiers to the actual modifiers sent to `hs.hotkey` +local convertModifiers = function(specifiedMods) + local actualMods, queueIndex = {}, 0 + + for _, v in pairs(specifiedMods) do + queueIndex = queueIndex | (modifierMasks[v] or 0) + local hotkeyModEquivalant = modiferBase[v] + if hotkeyModEquivalant then + table.insert(actualMods, hotkeyModEquivalant) + else + queueIndex = 0 + break + end + end + return actualMods, queueIndex +end + +-- eventtap and watchdog timer predefined so they stay local +local _flagWatcher, _watchTimer + +local enableAndDisableHotkeys = function(queueIndex) + local foundMatches = {} + for i, v in ipairs(queuedHotKeys) do + if i == queueIndex then + for key, _ in pairs(v) do + if key._enabled then + table.insert(foundMatches, key) +-- key._hotkey:enable() + end + end + else + for key, _ in pairs(v) do + if key._enabled then + key._hotkey:disable() + end + end + end + end + + if #foundMatches > 0 then + -- enable only the most recently created version for a given _keycode + -- in case of stacking + local enabled = {} + table.sort(foundMatches, function(a, b) return a._creationID > b._creationID end) + for _, key in ipairs(foundMatches) do + if not enabled[key._keycode] then + enabled[key._keycode] = true + key._hotkey:enable() + end + end + end +end + +-- respond to flag changes or (if ev is null) resynchronize +local flagChangeCallback = function(ev) + local rf = ev and ev:getRawEventData().CGEventData.flags + or eventtap.checkKeyboardModifiers(true)._raw + + local queueIndex = 0 + if rf & etevent.rawFlagMasks.deviceLeftAlternate > 0 then + queueIndex = queueIndex | modifierMasks.lalt + end + if rf & etevent.rawFlagMasks.deviceLeftCommand > 0 then + queueIndex = queueIndex | modifierMasks.lcmd + end + if rf & etevent.rawFlagMasks.deviceLeftControl > 0 then + queueIndex = queueIndex | modifierMasks.lctrl + end + if rf & etevent.rawFlagMasks.deviceLeftShift > 0 then + queueIndex = queueIndex | modifierMasks.lshift + end + if rf & etevent.rawFlagMasks.deviceRightAlternate > 0 then + queueIndex = queueIndex | modifierMasks.ralt + end + if rf & etevent.rawFlagMasks.deviceRightCommand > 0 then + queueIndex = queueIndex | modifierMasks.rcmd + end + if rf & etevent.rawFlagMasks.deviceRightControl > 0 then + queueIndex = queueIndex | modifierMasks.rctrl + end + if rf & etevent.rawFlagMasks.deviceRightShift > 0 then + queueIndex = queueIndex | modifierMasks.rshift + end +-- print("activating " .. tostring(queueIndex)) + + enableAndDisableHotkeys(queueIndex) +end + +-- checks that the flagwatcher is still running and synchronizes the callbacks +local checkFlagWatcher = function() + if not _flagWatcher:isEnabled() then + log.w("re-enabling flag watcher") + _flagWatcher:start() + flagChangeCallback(nil) + end +end + +-- define methods for our hotkey objects +local _LeftRightHotkeyObjMT = {} +_LeftRightHotkeyObjMT.__index = { + enable = function(self) + self._enabled = true + return self + end, + disable = function(self) + self._enabled = false + self._hotkey:disable() + return self + end, + delete = function(self) + self:disable() + existantHotKeys[self] = nil + collectgarbage() + return nil + end, + isEnabled = function(self) return self._enabled end, +} +_LeftRightHotkeyObjMT.__tostring = function(self) + return self._modDesc .. " " .. (keycodes.map[self._keycode] or ("unmapped:" .. tostring(self._keycode))) +end + +-- keeps track of creation order so we can enable only the latest enabled version +-- (i.e. stacking) +local definitionIndex = 0 + +---------- Spoon Methods ---------- + +--- LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject +--- Method +--- Create a new hotkey with the specified left/right specific modifiers. +--- +--- Parameters: +--- * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following: +--- * "lCmd", "lCommand", or "l⌘" for the left Command modifier +--- * "rCmd", "rCommand", or "r⌘" for the right Command modifier +--- * "lCtrl", "lControl" or "l⌃" for the left Control modifier +--- * "rCtrl", "rControl" or "r⌃" for the right Control modifier +--- * "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier +--- * "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier +--- * "lShift" or "l⇧" for the left Shift modifier +--- * "rShift" or "r⇧" for the right Shift modifier +--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number +--- * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown +--- * pressedfn - A function that will be called when the hotkey has been pressed, or nil +--- * releasedfn - A function that will be called when the hotkey has been released, or nil +--- * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil +--- +--- Returns: +--- * a new, initially disabled, hotkey with the specified left/right modifiers. +--- +--- Notes: +--- * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here. +obj.new = function(self, ...) + local args = { ... } + if self ~= obj then + table.insert(args, 1, self) + self = obj + end + local specifiedMods = normalizeModsTable(args[1]) + local actualMods, queueIndex = convertModifiers(specifiedMods) + + if queueIndex ~= 0 then + args[1] = actualMods + for i, v in ipairs(specifiedMods) do + specifiedMods[i] = v:sub(1,1) .. v:sub(2,2):upper() .. v:sub(3) + end + local key = args[2] + local keycode = keycodes.map[key] + if type(key) == "number" then keycode = key end +-- print(queueIndex, "actually " .. finspect(actualMods)) + local newObject = setmetatable({ + _modDesc = table.concat(specifiedMods, "+"), + _queueIndex = queueIndex, + _keycode = keycode, + _hotkey = hotkey.new(table.unpack(args)), + _enabled = false, + _creationID = definitionIndex, + }, _LeftRightHotkeyObjMT) + + -- used to determine creation order for stacking + definitionIndex = definitionIndex + 1 + + existantHotKeys[newObject] = true + queuedHotKeys[queueIndex][newObject] = true + return newObject + else + error("you must specifiy one or more of lcmd, rcmd, lshift, rshift, lalt, ralt, lctrl, rctrl", 2) + end +end + +--- LeftRightHotkey:deleteAll(mods, key) +--- Method +--- Deletes all previously set callbacks for a given keyboard combination +--- +--- Parameters: +--- * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following: +--- * "lCmd", "lCommand", or "l⌘" for the left Command modifier +--- * "rCmd", "rCommand", or "r⌘" for the right Command modifier +--- * "lCtrl", "lControl" or "l⌃" for the left Control modifier +--- * "rCtrl", "rControl" or "r⌃" for the right Control modifier +--- * "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier +--- * "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier +--- * "lShift" or "l⇧" for the left Shift modifier +--- * "rShift" or "r⇧" for the right Shift modifier +--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number +--- +--- Returns: +--- * None +obj.deleteAll = function(self, ...) + local args = { ... } + if self ~= obj then + table.insert(args, 1, self) + self = obj + end + local specifiedMods = normalizeModsTable(args[1]) + local _, queueIndex = convertModifiers(specifiedMods) + + if queueIndex ~= 0 then + local key = args[2] + local keycode = keycodes.map[key] + if type(key) == "number" then keycode = key end + + local foundMatches = {} + for k, v in pairs(existantHotKeys) do + if v._queueIndex == queueIndex and v._keycode == keycode then + table.insert(foundMatches, k) + end + end + -- this is so we don't remove items from existantHotKeys while iterating through it + for _, v in ipairs(foundMatches) do + v:delete() + end + else + error("you must specifiy one or more of lcmd, rcmd, lshift, rshift, lalt, ralt, lctrl, rctrl", 2) + end +end + +--- LeftRightHotkey:disableAll(mods, key) +--- Method +--- Disables all previously set callbacks for a given keyboard combination +--- +--- Parameters: +--- * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following: +--- * "lCmd", "lCommand", or "l⌘" for the left Command modifier +--- * "rCmd", "rCommand", or "r⌘" for the right Command modifier +--- * "lCtrl", "lControl" or "l⌃" for the left Control modifier +--- * "rCtrl", "rControl" or "r⌃" for the right Control modifier +--- * "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier +--- * "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier +--- * "lShift" or "l⇧" for the left Shift modifier +--- * "rShift" or "r⇧" for the right Shift modifier +--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number +--- +--- Returns: +--- * None +obj.disableAll = function(self, ...) + local args = { ... } + if self ~= obj then + table.insert(args, 1, self) + self = obj + end + local specifiedMods = normalizeModsTable(args[1]) + local _, queueIndex = convertModifiers(specifiedMods) + + if queueIndex ~= 0 then + local key = args[2] + local keycode = keycodes.map[key] + if type(key) == "number" then keycode = key end + + for k, v in pairs(existantHotKeys) do + if v._queueIndex == queueIndex and v._keycode == keycode then + k:disable() -- we don't need the temp table used in delete since we're just disabling + end + end + else + error("you must specifiy one or more of lcmd, rcmd, lshift, rshift, lalt, ralt, lctrl, rctrl", 2) + end +end + +--- LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject +--- Method +--- Create and enable a new hotkey with the specified left/right specific modifiers. +--- +--- Parameters: +--- Parameters: +--- * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following: +--- * "lCmd", "lCommand", or "l⌘" for the left Command modifier +--- * "rCmd", "rCommand", or "r⌘" for the right Command modifier +--- * "lCtrl", "lControl" or "l⌃" for the left Control modifier +--- * "rCtrl", "rControl" or "r⌃" for the right Control modifier +--- * "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier +--- * "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier +--- * "lShift" or "l⇧" for the left Shift modifier +--- * "rShift" or "r⇧" for the right Shift modifier +--- * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number +--- * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown +--- * pressedfn - A function that will be called when the hotkey has been pressed, or nil +--- * releasedfn - A function that will be called when the hotkey has been released, or nil +--- * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil +--- +--- Returns: +--- * a new enabled hotkey with the specified left/right modifiers. +--- +--- Notes: +--- * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()` +--- * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here. +obj.bind = function(...) return obj.new(...):enable() end + +--- LeftRightHotkey:start() -> self +--- Method +--- Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed. +--- +--- Parameters: +--- * None +--- +--- Returns: +--- * the LeftRightHotkey spoon object +--- +--- Notes: +--- * this enables the use of hotkeys created by using this Spoon. +obj.start = function(self) + -- in case called as function + if self ~= obj then self = obj end + if not _flagWatcher then + _flagWatcher = eventtap.new({ etevent.types.flagsChanged }, flagChangeCallback):start() + _watchTimer = timer.doEvery(1, checkFlagWatcher) +-- for debugging purposes, may go away + obj._flagWatcher = _flagWatcher + obj._watchTimer = _watchTimer + else + checkFlagWatcher() + end + return self +end + +--- LeftRightHotkey:stop() -> self +--- Method +--- Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed. +--- +--- Parameters: +--- * None +--- +--- Returns: +--- * the LeftRightHotkey spoon object +--- +--- Notes: +--- * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available. +obj.stop = function(self) + -- in case called as function + if self ~= obj then self = obj end + if _flagWatcher then + enableAndDisableHotkeys(0) + _flagWatcher:stop() + _flagWatcher = nil + _watchTimer:stop() + _watchTimer = nil +-- for debugging purposes, may go away + obj._flagWatcher = nil + obj._watchTimer = nil + end + return self +end + +-- Spoon Metadata definition and object return -- + +-- for debugging purposes, may go away +obj._queuedHotKeys = queuedHotKeys +obj._existantHotKeys = existantHotKeys + +return setmetatable(obj, { + -- more useful than "table: 0x????????????????" + __tostring = function(self) + local result, fieldSize = "", 0 + for i, v in ipairs(metadataKeys) do fieldSize = math.max(fieldSize, #v) end + for i, v in ipairs(metadataKeys) do + result = result .. string.format("%-"..tostring(fieldSize) .. "s %s\n", v, self[v]) + end + return result + end, +}) From f0496afe01b7c9f81d623d792f2c02eddfd2088e Mon Sep 17 00:00:00 2001 From: asmagill Date: Tue, 11 Jul 2023 19:21:22 +0100 Subject: [PATCH 02/55] docs file generated during merge --- Source/LeftRightHotkey.spoon/docs.json | 401 ------------------------- 1 file changed, 401 deletions(-) delete mode 100644 Source/LeftRightHotkey.spoon/docs.json diff --git a/Source/LeftRightHotkey.spoon/docs.json b/Source/LeftRightHotkey.spoon/docs.json deleted file mode 100644 index f283dfe4..00000000 --- a/Source/LeftRightHotkey.spoon/docs.json +++ /dev/null @@ -1,401 +0,0 @@ -[ - { - "Constant" : [ - - ], - "submodules" : [ - - ], - "Function" : [ - - ], - "Variable" : [ - - ], - "stripped_doc" : [ - - ], - "desc" : "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.", - "type" : "Module", - "Deprecated" : [ - - ], - "Constructor" : [ - - ], - "Field" : [ - - ], - "items" : [ - { - "desc" : "Create and enable a new hotkey with the specified left\/right specific modifiers.", - "def" : "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", - "stripped_doc" : [ - "Create and enable a new hotkey with the specified left\/right specific modifiers.", - "" - ], - "doc" : "Create and enable a new hotkey with the specified left\/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left\/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", - "notes" : [ - " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", - " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." - ], - "signature" : "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", - "type" : "Method", - "returns" : [ - " * a new enabled hotkey with the specified left\/right modifiers.", - "" - ], - "name" : "bind", - "parameters" : [ - " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", - " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", - " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", - " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", - " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", - " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", - " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", - " * \"lShift\" or \"l⇧\" for the left Shift modifier", - " * \"rShift\" or \"r⇧\" for the right Shift modifier", - " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", - " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", - " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", - " * releasedfn - A function that will be called when the hotkey has been released, or nil", - " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil", - "" - ] - }, - { - "desc" : "Deletes all previously set callbacks for a given keyboard combination", - "def" : "LeftRightHotkey:deleteAll(mods, key)", - "stripped_doc" : [ - "Deletes all previously set callbacks for a given keyboard combination", - "" - ], - "doc" : "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", - "notes" : [ - - ], - "signature" : "LeftRightHotkey:deleteAll(mods, key)", - "type" : "Method", - "returns" : [ - " * None" - ], - "name" : "deleteAll", - "parameters" : [ - " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", - " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", - " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", - " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", - " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", - " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", - " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", - " * \"lShift\" or \"l⇧\" for the left Shift modifier", - " * \"rShift\" or \"r⇧\" for the right Shift modifier", - " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", - "" - ] - }, - { - "desc" : "Disables all previously set callbacks for a given keyboard combination", - "def" : "LeftRightHotkey:disableAll(mods, key)", - "stripped_doc" : [ - "Disables all previously set callbacks for a given keyboard combination", - "" - ], - "doc" : "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", - "notes" : [ - - ], - "signature" : "LeftRightHotkey:disableAll(mods, key)", - "type" : "Method", - "returns" : [ - " * None" - ], - "name" : "disableAll", - "parameters" : [ - " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", - " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", - " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", - " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", - " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", - " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", - " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", - " * \"lShift\" or \"l⇧\" for the left Shift modifier", - " * \"rShift\" or \"r⇧\" for the right Shift modifier", - " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", - "" - ] - }, - { - "desc" : "Create a new hotkey with the specified left\/right specific modifiers.", - "def" : "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", - "stripped_doc" : [ - "Create a new hotkey with the specified left\/right specific modifiers.", - "" - ], - "doc" : "Create a new hotkey with the specified left\/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left\/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", - "notes" : [ - " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." - ], - "signature" : "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", - "type" : "Method", - "returns" : [ - " * a new, initially disabled, hotkey with the specified left\/right modifiers.", - "" - ], - "name" : "new", - "parameters" : [ - " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", - " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", - " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", - " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", - " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", - " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", - " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", - " * \"lShift\" or \"l⇧\" for the left Shift modifier", - " * \"rShift\" or \"r⇧\" for the right Shift modifier", - " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", - " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", - " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", - " * releasedfn - A function that will be called when the hotkey has been released, or nil", - " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil", - "" - ] - }, - { - "desc" : "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", - "def" : "LeftRightHotkey:start() -> self", - "stripped_doc" : [ - "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", - "" - ], - "doc" : "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", - "notes" : [ - " * this enables the use of hotkeys created by using this Spoon." - ], - "signature" : "LeftRightHotkey:start() -> self", - "type" : "Method", - "returns" : [ - " * the LeftRightHotkey spoon object", - "" - ], - "name" : "start", - "parameters" : [ - " * None", - "" - ] - }, - { - "desc" : "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", - "def" : "LeftRightHotkey:stop() -> self", - "stripped_doc" : [ - "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", - "" - ], - "doc" : "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", - "notes" : [ - " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." - ], - "signature" : "LeftRightHotkey:stop() -> self", - "type" : "Method", - "returns" : [ - " * the LeftRightHotkey spoon object", - "" - ], - "name" : "stop", - "parameters" : [ - " * None", - "" - ] - } - ], - "Command" : [ - - ], - "doc" : "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.\n\nThis is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon.\n\nThe `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents:\n\n * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey.\n * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey.\n * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey.\n * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)\n\nThe following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n\nThe modifiers table for any given hotkey is all inclusive; this means that if you specify `{ \"rShift\", \"lShift\" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either\/or, then stick with [hs.hotkey](hs.hotkey.html).\n\nAlternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon:\n e.g. `LeftRightHotkey:bind({ \"rCmd\", \"rShift\" }, \"a\", myFunction)` *and* `LeftRightHotkey:bind({ \"lCmd\", \"rShift\" }, \"a\", myFunction)`\n\nThis spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:\n * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.\n * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.\n * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary.\n * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled\/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.\n\nLike all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher.\n\nDownload: [https:\/\/github.com\/Hammerspoon\/Spoons\/raw\/master\/Spoons\/LeftRightHotkey.spoon.zip](https:\/\/github.com\/Hammerspoon\/Spoons\/raw\/master\/Spoons\/LeftRightHotkey.spoon.zip)", - "Method" : [ - { - "desc" : "Create a new hotkey with the specified left\/right specific modifiers.", - "def" : "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", - "stripped_doc" : [ - "Create a new hotkey with the specified left\/right specific modifiers.", - "" - ], - "doc" : "Create a new hotkey with the specified left\/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left\/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", - "notes" : [ - " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." - ], - "signature" : "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", - "type" : "Method", - "returns" : [ - " * a new, initially disabled, hotkey with the specified left\/right modifiers.", - "" - ], - "name" : "new", - "parameters" : [ - " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", - " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", - " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", - " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", - " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", - " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", - " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", - " * \"lShift\" or \"l⇧\" for the left Shift modifier", - " * \"rShift\" or \"r⇧\" for the right Shift modifier", - " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", - " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", - " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", - " * releasedfn - A function that will be called when the hotkey has been released, or nil", - " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil", - "" - ] - }, - { - "desc" : "Deletes all previously set callbacks for a given keyboard combination", - "def" : "LeftRightHotkey:deleteAll(mods, key)", - "stripped_doc" : [ - "Deletes all previously set callbacks for a given keyboard combination", - "" - ], - "doc" : "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", - "notes" : [ - - ], - "signature" : "LeftRightHotkey:deleteAll(mods, key)", - "type" : "Method", - "returns" : [ - " * None" - ], - "name" : "deleteAll", - "parameters" : [ - " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", - " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", - " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", - " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", - " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", - " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", - " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", - " * \"lShift\" or \"l⇧\" for the left Shift modifier", - " * \"rShift\" or \"r⇧\" for the right Shift modifier", - " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", - "" - ] - }, - { - "desc" : "Disables all previously set callbacks for a given keyboard combination", - "def" : "LeftRightHotkey:disableAll(mods, key)", - "stripped_doc" : [ - "Disables all previously set callbacks for a given keyboard combination", - "" - ], - "doc" : "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", - "notes" : [ - - ], - "signature" : "LeftRightHotkey:disableAll(mods, key)", - "type" : "Method", - "returns" : [ - " * None" - ], - "name" : "disableAll", - "parameters" : [ - " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", - " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", - " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", - " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", - " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", - " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", - " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", - " * \"lShift\" or \"l⇧\" for the left Shift modifier", - " * \"rShift\" or \"r⇧\" for the right Shift modifier", - " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", - "" - ] - }, - { - "desc" : "Create and enable a new hotkey with the specified left\/right specific modifiers.", - "def" : "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", - "stripped_doc" : [ - "Create and enable a new hotkey with the specified left\/right specific modifiers.", - "" - ], - "doc" : "Create and enable a new hotkey with the specified left\/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left\/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", - "notes" : [ - " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", - " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." - ], - "signature" : "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", - "type" : "Method", - "returns" : [ - " * a new enabled hotkey with the specified left\/right modifiers.", - "" - ], - "name" : "bind", - "parameters" : [ - " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:", - " * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier", - " * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier", - " * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier", - " * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier", - " * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier", - " * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier", - " * \"lShift\" or \"l⇧\" for the left Shift modifier", - " * \"rShift\" or \"r⇧\" for the right Shift modifier", - " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", - " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", - " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", - " * releasedfn - A function that will be called when the hotkey has been released, or nil", - " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil", - "" - ] - }, - { - "desc" : "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", - "def" : "LeftRightHotkey:start() -> self", - "stripped_doc" : [ - "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", - "" - ], - "doc" : "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", - "notes" : [ - " * this enables the use of hotkeys created by using this Spoon." - ], - "signature" : "LeftRightHotkey:start() -> self", - "type" : "Method", - "returns" : [ - " * the LeftRightHotkey spoon object", - "" - ], - "name" : "start", - "parameters" : [ - " * None", - "" - ] - }, - { - "desc" : "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", - "def" : "LeftRightHotkey:stop() -> self", - "stripped_doc" : [ - "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", - "" - ], - "doc" : "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", - "notes" : [ - " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." - ], - "signature" : "LeftRightHotkey:stop() -> self", - "type" : "Method", - "returns" : [ - " * the LeftRightHotkey spoon object", - "" - ], - "name" : "stop", - "parameters" : [ - " * None", - "" - ] - } - ], - "name" : "LeftRightHotkey" - } -] From 6ba06f88c83dd3b05997832762ec886b452e4a1e Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Sun, 2 Jun 2024 02:01:16 +0000 Subject: [PATCH 03/55] Generate docs for LeftRightHotkey --- Source/LeftRightHotkey.spoon/docs.json | 291 +++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 Source/LeftRightHotkey.spoon/docs.json diff --git a/Source/LeftRightHotkey.spoon/docs.json b/Source/LeftRightHotkey.spoon/docs.json new file mode 100644 index 00000000..7068e1b6 --- /dev/null +++ b/Source/LeftRightHotkey.spoon/docs.json @@ -0,0 +1,291 @@ +[ + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create and enable a new hotkey with the specified left/right specific modifiers.", + "doc": "Create and enable a new hotkey with the specified left/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "415", + "name": "bind", + "notes": [ + " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." + ], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "returns": [ + " * a new enabled hotkey with the specified left/right modifiers." + ], + "signature": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:deleteAll(mods, key)", + "desc": "Deletes all previously set callbacks for a given keyboard combination", + "doc": "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "326", + "name": "deleteAll", + "notes": [], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "returns": [ + " * None" + ], + "signature": "LeftRightHotkey:deleteAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:disableAll(mods, key)", + "desc": "Disables all previously set callbacks for a given keyboard combination", + "doc": "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "373", + "name": "disableAll", + "notes": [], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "returns": [ + " * None" + ], + "signature": "LeftRightHotkey:disableAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create a new hotkey with the specified left/right specific modifiers.", + "doc": "Create a new hotkey with the specified left/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "263", + "name": "new", + "notes": [ + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." + ], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "returns": [ + " * a new, initially disabled, hotkey with the specified left/right modifiers." + ], + "signature": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:start() -> self", + "desc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "doc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "444", + "name": "start", + "notes": [ + " * this enables the use of hotkeys created by using this Spoon." + ], + "parameters": [ + " * None" + ], + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "signature": "LeftRightHotkey:start() -> self", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:stop() -> self", + "desc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "doc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "471", + "name": "stop", + "notes": [ + " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." + ], + "parameters": [ + " * None" + ], + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "signature": "LeftRightHotkey:stop() -> self", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [], + "desc": "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.", + "doc": "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.\n\nThis is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon.\n\nThe `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents:\n\n * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey.\n * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey.\n * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey.\n * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)\n\nThe following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n\nThe modifiers table for any given hotkey is all inclusive; this means that if you specify `{ \"rShift\", \"lShift\" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either/or, then stick with [hs.hotkey](hs.hotkey.html).\n\nAlternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon:\n e.g. `LeftRightHotkey:bind({ \"rCmd\", \"rShift\" }, \"a\", myFunction)` *and* `LeftRightHotkey:bind({ \"lCmd\", \"rShift\" }, \"a\", myFunction)`\n\nThis spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:\n * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.\n * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.\n * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary.\n * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.\n\nLike all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip)", + "items": [ + { + "def": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create and enable a new hotkey with the specified left/right specific modifiers.", + "doc": "Create and enable a new hotkey with the specified left/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "415", + "name": "bind", + "notes": [ + " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." + ], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "returns": [ + " * a new enabled hotkey with the specified left/right modifiers." + ], + "signature": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:deleteAll(mods, key)", + "desc": "Deletes all previously set callbacks for a given keyboard combination", + "doc": "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "326", + "name": "deleteAll", + "notes": [], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "returns": [ + " * None" + ], + "signature": "LeftRightHotkey:deleteAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:disableAll(mods, key)", + "desc": "Disables all previously set callbacks for a given keyboard combination", + "doc": "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "373", + "name": "disableAll", + "notes": [], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "returns": [ + " * None" + ], + "signature": "LeftRightHotkey:disableAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create a new hotkey with the specified left/right specific modifiers.", + "doc": "Create a new hotkey with the specified left/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "263", + "name": "new", + "notes": [ + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." + ], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "returns": [ + " * a new, initially disabled, hotkey with the specified left/right modifiers." + ], + "signature": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:start() -> self", + "desc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "doc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "444", + "name": "start", + "notes": [ + " * this enables the use of hotkeys created by using this Spoon." + ], + "parameters": [ + " * None" + ], + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "signature": "LeftRightHotkey:start() -> self", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:stop() -> self", + "desc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "doc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon//init.lua", + "lineno": "471", + "name": "stop", + "notes": [ + " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." + ], + "parameters": [ + " * None" + ], + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "signature": "LeftRightHotkey:stop() -> self", + "stripped_doc": "", + "type": "Method" + } + ], + "name": "LeftRightHotkey", + "stripped_doc": "\nThis is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon.\n\nThe `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents:\n\n * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey.\n * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey.\n * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey.\n * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)\n\nThe following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n\nThe modifiers table for any given hotkey is all inclusive; this means that if you specify `{ \"rShift\", \"lShift\" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either/or, then stick with [hs.hotkey](hs.hotkey.html).\n\nAlternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon:\n e.g. `LeftRightHotkey:bind({ \"rCmd\", \"rShift\" }, \"a\", myFunction)` *and* `LeftRightHotkey:bind({ \"lCmd\", \"rShift\" }, \"a\", myFunction)`\n\nThis spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:\n * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.\n * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.\n * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary.\n * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.\n\nLike all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip)", + "submodules": [], + "type": "Module" + } +] \ No newline at end of file From f11d042ba2212cfe69f4f680b1b219800bb8755e Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Sun, 2 Jun 2024 02:01:17 +0000 Subject: [PATCH 04/55] Add binary package for LeftRightHotkey. --- Spoons/LeftRightHotkey.spoon.zip | Bin 0 -> 8929 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Spoons/LeftRightHotkey.spoon.zip diff --git a/Spoons/LeftRightHotkey.spoon.zip b/Spoons/LeftRightHotkey.spoon.zip new file mode 100644 index 0000000000000000000000000000000000000000..b16e539d2a531750c0576c5e7febe25dd4c0906a GIT binary patch literal 8929 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 G8vO_5@SO4h literal 0 HcmV?d00001 From 70341ddc6ffeebc74f8264d9b2c52da0ee29060b Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Sun, 2 Jun 2024 02:01:17 +0000 Subject: [PATCH 05/55] Update docs --- docs/LeftRightHotkey.html | 372 ++++++++++++++++++++++++++++++++++++++ docs/docs.json | 289 +++++++++++++++++++++++++++++ docs/docs_index.json | 41 +++++ docs/index.html | 5 + docs/templated_docs.json | 363 +++++++++++++++++++++++++++++++++++++ 5 files changed, 1070 insertions(+) create mode 100644 docs/LeftRightHotkey.html diff --git a/docs/LeftRightHotkey.html b/docs/LeftRightHotkey.html new file mode 100644 index 00000000..1fbd7613 --- /dev/null +++ b/docs/LeftRightHotkey.html @@ -0,0 +1,372 @@ + + + + Hammerspoon docs: LeftRightHotkey + + + + +
+

docs » LeftRightHotkey

+

This spoon addresses a limitation within the hs.hotkey module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.

+

This is accomplished by creating unactivated hotkeys for each definition and using an hs.eventtap watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the bind and new methods of this spoon.

+

The LeftRightHotkeyObject that is returned by LeftRightHotkey:new and LeftRightHotkey:bind supports the following methods in a manner similar to the hs.hotkey equivalents:

+
    +
  • LeftRightHotkeyObject:enable() -- enables the registered hotkey.
  • +
  • LeftRightHotkeyObject:disable() -- disables the registered hotkey.
  • +
  • LeftRightHotkeyObject:delete() -- deletes the registered hotkey.
  • +
  • `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)
  • +
+

The following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:

+
    +
  • "lCmd", "lCommand", or "l⌘" for the left Command modifier
  • +
  • "rCmd", "rCommand", or "r⌘" for the right Command modifier
  • +
  • "lCtrl", "lControl" or "l⌃" for the left Control modifier
  • +
  • "rCtrl", "rControl" or "r⌃" for the right Control modifier
  • +
  • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
  • +
  • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
  • +
  • "lShift" or "l⇧" for the left Shift modifier
  • +
  • "rShift" or "r⇧" for the right Shift modifier
  • +
+

The modifiers table for any given hotkey is all inclusive; this means that if you specify { "rShift", "lShift" } then both the left and right shift keys must be pressed to trigger the hotkey -- if you want either/or, then stick with hs.hotkey.

+

Alternatively, if you want to setup a hotkey when either command key is pressed with only the right shift, you would need to set up two hotkeys with this spoon: + e.g. LeftRightHotkey:bind({ "rCmd", "rShift" }, "a", myFunction) and LeftRightHotkey:bind({ "lCmd", "rShift" }, "a", myFunction)

+

This spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:

+
    +
  • like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.
  • +
  • behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through hs.hotkey:enable() -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.
      +
    • a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue LeftRightHotkey:start() to force the eventtap to be reset if necessary.
    • +
    • if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.
    • +
    +
  • +
+

Like all Spoons, don't forget to use the LeftRightHotkey:start() method to activate the modifier key watcher.

+

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip

+ +
+

API Overview

+ +

API Documentation

+

Methods

+
+ +
bind
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureLeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject
TypeMethod
Description

Create and enable a new hotkey with the specified left/right specific modifiers.

+
Parameters
    +
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      +
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • +
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • +
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • +
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • +
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • +
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • +
    • "lShift" or "l⇧" for the left Shift modifier
    • +
    • "rShift" or "r⇧" for the right Shift modifier
    • +
    +
  • +
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • +
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • +
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • +
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • +
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • +
+
Returns
    +
  • a new enabled hotkey with the specified left/right modifiers.
  • +
+
Notes
    +
  • This function is just a wrapper that performs LeftRightHotkey:new(...):enable()
  • +
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.bind as is and any caveats or considerations outlined there also apply here.
  • +
+
SourceSource/LeftRightHotkey.spoon/init.lua line 415
+
+
+ +
deleteAll
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureLeftRightHotkey:deleteAll(mods, key)
TypeMethod
Description

Deletes all previously set callbacks for a given keyboard combination

+
Parameters
    +
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      +
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • +
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • +
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • +
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • +
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • +
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • +
    • "lShift" or "l⇧" for the left Shift modifier
    • +
    • "rShift" or "r⇧" for the right Shift modifier
    • +
    +
  • +
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • +
+
Returns
    +
  • None
  • +
+
SourceSource/LeftRightHotkey.spoon/init.lua line 326
+
+
+ +
disableAll
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureLeftRightHotkey:disableAll(mods, key)
TypeMethod
Description

Disables all previously set callbacks for a given keyboard combination

+
Parameters
    +
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      +
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • +
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • +
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • +
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • +
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • +
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • +
    • "lShift" or "l⇧" for the left Shift modifier
    • +
    • "rShift" or "r⇧" for the right Shift modifier
    • +
    +
  • +
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • +
+
Returns
    +
  • None
  • +
+
SourceSource/LeftRightHotkey.spoon/init.lua line 373
+
+
+ +
new
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureLeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject
TypeMethod
Description

Create a new hotkey with the specified left/right specific modifiers.

+
Parameters
    +
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      +
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • +
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • +
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • +
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • +
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • +
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • +
    • "lShift" or "l⇧" for the left Shift modifier
    • +
    • "rShift" or "r⇧" for the right Shift modifier
    • +
    +
  • +
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • +
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • +
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • +
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • +
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • +
+
Returns
    +
  • a new, initially disabled, hotkey with the specified left/right modifiers.
  • +
+
Notes
    +
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.new as is and any caveats or considerations outlined there also apply here.
  • +
+
SourceSource/LeftRightHotkey.spoon/init.lua line 263
+
+
+ +
start
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureLeftRightHotkey:start() -> self
TypeMethod
Description

Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

+
Parameters
    +
  • None
  • +
+
Returns
    +
  • the LeftRightHotkey spoon object
  • +
+
Notes
    +
  • this enables the use of hotkeys created by using this Spoon.
  • +
+
SourceSource/LeftRightHotkey.spoon/init.lua line 444
+
+
+ +
stop
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureLeftRightHotkey:stop() -> self
TypeMethod
Description

Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

+
Parameters
    +
  • None
  • +
+
Returns
    +
  • the LeftRightHotkey spoon object
  • +
+
Notes
    +
  • this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with hs.hotkey directly will still be available.
  • +
+
SourceSource/LeftRightHotkey.spoon/init.lua line 471
+
+ + \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index ccfaede9..e3f8d4c5 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -7603,6 +7603,295 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create and enable a new hotkey with the specified left/right specific modifiers.", + "doc": "Create and enable a new hotkey with the specified left/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "415", + "name": "bind", + "notes": [ + " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." + ], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "returns": [ + " * a new enabled hotkey with the specified left/right modifiers." + ], + "signature": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:deleteAll(mods, key)", + "desc": "Deletes all previously set callbacks for a given keyboard combination", + "doc": "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "326", + "name": "deleteAll", + "notes": [], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "returns": [ + " * None" + ], + "signature": "LeftRightHotkey:deleteAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:disableAll(mods, key)", + "desc": "Disables all previously set callbacks for a given keyboard combination", + "doc": "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "373", + "name": "disableAll", + "notes": [], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "returns": [ + " * None" + ], + "signature": "LeftRightHotkey:disableAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create a new hotkey with the specified left/right specific modifiers.", + "doc": "Create a new hotkey with the specified left/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "263", + "name": "new", + "notes": [ + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." + ], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "returns": [ + " * a new, initially disabled, hotkey with the specified left/right modifiers." + ], + "signature": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:start() -> self", + "desc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "doc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "444", + "name": "start", + "notes": [ + " * this enables the use of hotkeys created by using this Spoon." + ], + "parameters": [ + " * None" + ], + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "signature": "LeftRightHotkey:start() -> self", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:stop() -> self", + "desc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "doc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "471", + "name": "stop", + "notes": [ + " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." + ], + "parameters": [ + " * None" + ], + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "signature": "LeftRightHotkey:stop() -> self", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [], + "desc": "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.", + "doc": "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.\n\nThis is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon.\n\nThe `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents:\n\n * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey.\n * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey.\n * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey.\n * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)\n\nThe following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n\nThe modifiers table for any given hotkey is all inclusive; this means that if you specify `{ \"rShift\", \"lShift\" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either/or, then stick with [hs.hotkey](hs.hotkey.html).\n\nAlternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon:\n e.g. `LeftRightHotkey:bind({ \"rCmd\", \"rShift\" }, \"a\", myFunction)` *and* `LeftRightHotkey:bind({ \"lCmd\", \"rShift\" }, \"a\", myFunction)`\n\nThis spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:\n * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.\n * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.\n * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary.\n * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.\n\nLike all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip)", + "items": [ + { + "def": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create and enable a new hotkey with the specified left/right specific modifiers.", + "doc": "Create and enable a new hotkey with the specified left/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "415", + "name": "bind", + "notes": [ + " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." + ], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "returns": [ + " * a new enabled hotkey with the specified left/right modifiers." + ], + "signature": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:deleteAll(mods, key)", + "desc": "Deletes all previously set callbacks for a given keyboard combination", + "doc": "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "326", + "name": "deleteAll", + "notes": [], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "returns": [ + " * None" + ], + "signature": "LeftRightHotkey:deleteAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:disableAll(mods, key)", + "desc": "Disables all previously set callbacks for a given keyboard combination", + "doc": "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "373", + "name": "disableAll", + "notes": [], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "returns": [ + " * None" + ], + "signature": "LeftRightHotkey:disableAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create a new hotkey with the specified left/right specific modifiers.", + "doc": "Create a new hotkey with the specified left/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "263", + "name": "new", + "notes": [ + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." + ], + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "returns": [ + " * a new, initially disabled, hotkey with the specified left/right modifiers." + ], + "signature": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:start() -> self", + "desc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "doc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "444", + "name": "start", + "notes": [ + " * this enables the use of hotkeys created by using this Spoon." + ], + "parameters": [ + " * None" + ], + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "signature": "LeftRightHotkey:start() -> self", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:stop() -> self", + "desc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "doc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "471", + "name": "stop", + "notes": [ + " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." + ], + "parameters": [ + " * None" + ], + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "signature": "LeftRightHotkey:stop() -> self", + "stripped_doc": "", + "type": "Method" + } + ], + "name": "LeftRightHotkey", + "stripped_doc": "\nThis is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon.\n\nThe `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents:\n\n * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey.\n * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey.\n * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey.\n * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)\n\nThe following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n\nThe modifiers table for any given hotkey is all inclusive; this means that if you specify `{ \"rShift\", \"lShift\" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either/or, then stick with [hs.hotkey](hs.hotkey.html).\n\nAlternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon:\n e.g. `LeftRightHotkey:bind({ \"rCmd\", \"rShift\" }, \"a\", myFunction)` *and* `LeftRightHotkey:bind({ \"lCmd\", \"rShift\" }, \"a\", myFunction)`\n\nThis spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:\n * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.\n * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.\n * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary.\n * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.\n\nLike all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], diff --git a/docs/docs_index.json b/docs/docs_index.json index 3d07f39c..169bce42 100644 --- a/docs/docs_index.json +++ b/docs/docs_index.json @@ -1444,6 +1444,47 @@ "name": "stop", "type": "Method" }, + { + "desc": "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.", + "name": "LeftRightHotkey", + "type": "Module" + }, + { + "desc": "Create and enable a new hotkey with the specified left/right specific modifiers.", + "module": "LeftRightHotkey", + "name": "bind", + "type": "Method" + }, + { + "desc": "Deletes all previously set callbacks for a given keyboard combination", + "module": "LeftRightHotkey", + "name": "deleteAll", + "type": "Method" + }, + { + "desc": "Disables all previously set callbacks for a given keyboard combination", + "module": "LeftRightHotkey", + "name": "disableAll", + "type": "Method" + }, + { + "desc": "Create a new hotkey with the specified left/right specific modifiers.", + "module": "LeftRightHotkey", + "name": "new", + "type": "Method" + }, + { + "desc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "module": "LeftRightHotkey", + "name": "start", + "type": "Method" + }, + { + "desc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "module": "LeftRightHotkey", + "name": "stop", + "type": "Method" + }, { "desc": "Show a popup window with the currently selected word in lexicon, notes, online help", "name": "LookupSelection", diff --git a/docs/index.html b/docs/index.html index 66379d2e..e6221855 100644 --- a/docs/index.html +++ b/docs/index.html @@ -252,6 +252,11 @@

API documentation

Leanpub

Spoon to track and notify about Leanpub builds.

+ + + + LeftRightHotkey +

This spoon addresses a limitation within the hs.hotkey module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.

diff --git a/docs/templated_docs.json b/docs/templated_docs.json index 751990a2..b8240850 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -9715,6 +9715,369 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "def_gfm": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create and enable a new hotkey with the specified left/right specific modifiers.", + "desc_gfm": "

Create and enable a new hotkey with the specified left/right specific modifiers.

\n", + "doc": "Create and enable a new hotkey with the specified left/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", + "doc_gfm": "

Create and enable a new hotkey with the specified left/right specific modifiers.

\n

Parameters:\nParameters:

\n
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • \n
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • \n
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • \n
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • \n
\n

Returns:

\n
    \n
  • a new enabled hotkey with the specified left/right modifiers.
  • \n
\n

Notes:

\n
    \n
  • This function is just a wrapper that performs LeftRightHotkey:new(...):enable()
  • \n
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.bind as is and any caveats or considerations outlined there also apply here.
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "415", + "name": "bind", + "notes": [ + " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." + ], + "notes_gfm": "
    \n
  • This function is just a wrapper that performs LeftRightHotkey:new(...):enable()
  • \n
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.bind as is and any caveats or considerations outlined there also apply here.
  • \n
\n", + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "parameters_gfm": "
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • \n
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • \n
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • \n
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • \n
\n", + "returns": [ + " * a new enabled hotkey with the specified left/right modifiers." + ], + "returns_gfm": "
    \n
  • a new enabled hotkey with the specified left/right modifiers.
  • \n
\n", + "signature": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:deleteAll(mods, key)", + "def_gfm": "LeftRightHotkey:deleteAll(mods, key)", + "desc": "Deletes all previously set callbacks for a given keyboard combination", + "desc_gfm": "

Deletes all previously set callbacks for a given keyboard combination

\n", + "doc": "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "doc_gfm": "

Deletes all previously set callbacks for a given keyboard combination

\n

Parameters:

\n
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
\n

Returns:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "326", + "name": "deleteAll", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "parameters_gfm": "
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
\n", + "returns": [ + " * None" + ], + "returns_gfm": "
    \n
  • None
  • \n
\n", + "signature": "LeftRightHotkey:deleteAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:disableAll(mods, key)", + "def_gfm": "LeftRightHotkey:disableAll(mods, key)", + "desc": "Disables all previously set callbacks for a given keyboard combination", + "desc_gfm": "

Disables all previously set callbacks for a given keyboard combination

\n", + "doc": "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "doc_gfm": "

Disables all previously set callbacks for a given keyboard combination

\n

Parameters:

\n
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
\n

Returns:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "373", + "name": "disableAll", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "parameters_gfm": "
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
\n", + "returns": [ + " * None" + ], + "returns_gfm": "
    \n
  • None
  • \n
\n", + "signature": "LeftRightHotkey:disableAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "def_gfm": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create a new hotkey with the specified left/right specific modifiers.", + "desc_gfm": "

Create a new hotkey with the specified left/right specific modifiers.

\n", + "doc": "Create a new hotkey with the specified left/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", + "doc_gfm": "

Create a new hotkey with the specified left/right specific modifiers.

\n

Parameters:

\n
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • \n
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • \n
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • \n
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • \n
\n

Returns:

\n
    \n
  • a new, initially disabled, hotkey with the specified left/right modifiers.
  • \n
\n

Notes:

\n
    \n
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.new as is and any caveats or considerations outlined there also apply here.
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "263", + "name": "new", + "notes": [ + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." + ], + "notes_gfm": "
    \n
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.new as is and any caveats or considerations outlined there also apply here.
  • \n
\n", + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "parameters_gfm": "
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • \n
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • \n
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • \n
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • \n
\n", + "returns": [ + " * a new, initially disabled, hotkey with the specified left/right modifiers." + ], + "returns_gfm": "
    \n
  • a new, initially disabled, hotkey with the specified left/right modifiers.
  • \n
\n", + "signature": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:start() -> self", + "def_gfm": "LeftRightHotkey:start() -> self", + "desc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "desc_gfm": "

Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

\n", + "doc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", + "doc_gfm": "

Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • the LeftRightHotkey spoon object
  • \n
\n

Notes:

\n
    \n
  • this enables the use of hotkeys created by using this Spoon.
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "444", + "name": "start", + "notes": [ + " * this enables the use of hotkeys created by using this Spoon." + ], + "notes_gfm": "
    \n
  • this enables the use of hotkeys created by using this Spoon.
  • \n
\n", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "returns_gfm": "
    \n
  • the LeftRightHotkey spoon object
  • \n
\n", + "signature": "LeftRightHotkey:start() -> self", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:stop() -> self", + "def_gfm": "LeftRightHotkey:stop() -> self", + "desc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "desc_gfm": "

Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

\n", + "doc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", + "doc_gfm": "

Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • the LeftRightHotkey spoon object
  • \n
\n

Notes:

\n
    \n
  • this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with hs.hotkey directly will still be available.
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "471", + "name": "stop", + "notes": [ + " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." + ], + "notes_gfm": "
    \n
  • this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with hs.hotkey directly will still be available.
  • \n
\n", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "returns_gfm": "
    \n
  • the LeftRightHotkey spoon object
  • \n
\n", + "signature": "LeftRightHotkey:stop() -> self", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [], + "desc": "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.", + "desc_gfm": "

This spoon addresses a limitation within the hs.hotkey module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.

\n", + "doc": "This spoon addresses a limitation within the [hs.hotkey](hs.hotkey.html) module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.\n\nThis is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon.\n\nThe `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents:\n\n * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey.\n * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey.\n * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey.\n * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)\n\nThe following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n\nThe modifiers table for any given hotkey is all inclusive; this means that if you specify `{ \"rShift\", \"lShift\" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either/or, then stick with [hs.hotkey](hs.hotkey.html).\n\nAlternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon:\n e.g. `LeftRightHotkey:bind({ \"rCmd\", \"rShift\" }, \"a\", myFunction)` *and* `LeftRightHotkey:bind({ \"lCmd\", \"rShift\" }, \"a\", myFunction)`\n\nThis spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:\n * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.\n * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.\n * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary.\n * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.\n\nLike all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip)", + "doc_gfm": "

This spoon addresses a limitation within the hs.hotkey module that allows the creation of hotkeys bound to specific left or right keyboard modifiers while leaving the other side free.

\n

This is accomplished by creating unactivated hotkeys for each definition and using an hs.eventtap watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the bind and new methods of this spoon.

\n

The LeftRightHotkeyObject that is returned by LeftRightHotkey:new and LeftRightHotkey:bind supports the following methods in a manner similar to the hs.hotkey equivalents:

\n
    \n
  • LeftRightHotkeyObject:enable() -- enables the registered hotkey.
  • \n
  • LeftRightHotkeyObject:disable() -- disables the registered hotkey.
  • \n
  • LeftRightHotkeyObject:delete() -- deletes the registered hotkey.
  • \n
  • `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)
  • \n
\n

The following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:

\n
    \n
  • "lCmd", "lCommand", or "l⌘" for the left Command modifier
  • \n
  • "rCmd", "rCommand", or "r⌘" for the right Command modifier
  • \n
  • "lCtrl", "lControl" or "l⌃" for the left Control modifier
  • \n
  • "rCtrl", "rControl" or "r⌃" for the right Control modifier
  • \n
  • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
  • \n
  • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
  • \n
  • "lShift" or "l⇧" for the left Shift modifier
  • \n
  • "rShift" or "r⇧" for the right Shift modifier
  • \n
\n

The modifiers table for any given hotkey is all inclusive; this means that if you specify { "rShift", "lShift" } then both the left and right shift keys must be pressed to trigger the hotkey -- if you want either/or, then stick with hs.hotkey.

\n

Alternatively, if you want to setup a hotkey when either command key is pressed with only the right shift, you would need to set up two hotkeys with this spoon:\n e.g. LeftRightHotkey:bind({ "rCmd", "rShift" }, "a", myFunction) and LeftRightHotkey:bind({ "lCmd", "rShift" }, "a", myFunction)

\n

This spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:

\n
    \n
  • like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.
  • \n
  • behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through hs.hotkey:enable() -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.
      \n
    • a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue LeftRightHotkey:start() to force the eventtap to be reset if necessary.
    • \n
    • if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.
    • \n
    \n
  • \n
\n

Like all Spoons, don't forget to use the LeftRightHotkey:start() method to activate the modifier key watcher.

\n

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip

\n", + "items": [ + { + "def": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "def_gfm": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create and enable a new hotkey with the specified left/right specific modifiers.", + "desc_gfm": "

Create and enable a new hotkey with the specified left/right specific modifiers.

\n", + "doc": "Create and enable a new hotkey with the specified left/right specific modifiers.\n\nParameters:\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new enabled hotkey with the specified left/right modifiers.\n\nNotes:\n * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here.", + "doc_gfm": "

Create and enable a new hotkey with the specified left/right specific modifiers.

\n

Parameters:\nParameters:

\n
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • \n
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • \n
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • \n
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • \n
\n

Returns:

\n
    \n
  • a new enabled hotkey with the specified left/right modifiers.
  • \n
\n

Notes:

\n
    \n
  • This function is just a wrapper that performs LeftRightHotkey:new(...):enable()
  • \n
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.bind as is and any caveats or considerations outlined there also apply here.
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "415", + "name": "bind", + "notes": [ + " * This function is just a wrapper that performs `LeftRightHotkey:new(...):enable()`", + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.bind](hs.hotkey.html#bind) as is and any caveats or considerations outlined there also apply here." + ], + "notes_gfm": "
    \n
  • This function is just a wrapper that performs LeftRightHotkey:new(...):enable()
  • \n
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.bind as is and any caveats or considerations outlined there also apply here.
  • \n
\n", + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "parameters_gfm": "
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • \n
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • \n
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • \n
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • \n
\n", + "returns": [ + " * a new enabled hotkey with the specified left/right modifiers." + ], + "returns_gfm": "
    \n
  • a new enabled hotkey with the specified left/right modifiers.
  • \n
\n", + "signature": "LeftRightHotkey:bind(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:deleteAll(mods, key)", + "def_gfm": "LeftRightHotkey:deleteAll(mods, key)", + "desc": "Deletes all previously set callbacks for a given keyboard combination", + "desc_gfm": "

Deletes all previously set callbacks for a given keyboard combination

\n", + "doc": "Deletes all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "doc_gfm": "

Deletes all previously set callbacks for a given keyboard combination

\n

Parameters:

\n
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
\n

Returns:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "326", + "name": "deleteAll", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "parameters_gfm": "
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
\n", + "returns": [ + " * None" + ], + "returns_gfm": "
    \n
  • None
  • \n
\n", + "signature": "LeftRightHotkey:deleteAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:disableAll(mods, key)", + "def_gfm": "LeftRightHotkey:disableAll(mods, key)", + "desc": "Disables all previously set callbacks for a given keyboard combination", + "desc_gfm": "

Disables all previously set callbacks for a given keyboard combination

\n", + "doc": "Disables all previously set callbacks for a given keyboard combination\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n\nReturns:\n * None", + "doc_gfm": "

Disables all previously set callbacks for a given keyboard combination

\n

Parameters:

\n
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
\n

Returns:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "373", + "name": "disableAll", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number" + ], + "parameters_gfm": "
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
\n", + "returns": [ + " * None" + ], + "returns_gfm": "
    \n
  • None
  • \n
\n", + "signature": "LeftRightHotkey:disableAll(mods, key)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "def_gfm": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "desc": "Create a new hotkey with the specified left/right specific modifiers.", + "desc_gfm": "

Create a new hotkey with the specified left/right specific modifiers.

\n", + "doc": "Create a new hotkey with the specified left/right specific modifiers.\n\nParameters:\n * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number\n * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown\n * pressedfn - A function that will be called when the hotkey has been pressed, or nil\n * releasedfn - A function that will be called when the hotkey has been released, or nil\n * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil\n\nReturns:\n * a new, initially disabled, hotkey with the specified left/right modifiers.\n\nNotes:\n * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here.", + "doc_gfm": "

Create a new hotkey with the specified left/right specific modifiers.

\n

Parameters:

\n
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • \n
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • \n
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • \n
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • \n
\n

Returns:

\n
    \n
  • a new, initially disabled, hotkey with the specified left/right modifiers.
  • \n
\n

Notes:

\n
    \n
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.new as is and any caveats or considerations outlined there also apply here.
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "263", + "name": "new", + "notes": [ + " * The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to [hs.hotkey.new](hs.hotkey.html#new) as is and any caveats or considerations outlined there also apply here." + ], + "notes_gfm": "
    \n
  • The modifiers table is adjusted for use when conditionally activating the appropriate hotkeys based on the current modifiers in effect, but the other arguments are passed to hs.hotkey.new as is and any caveats or considerations outlined there also apply here.
  • \n
\n", + "parameters": [ + " * mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier", + " * key - A string containing the name of a keyboard key (as found in [hs.keycodes.map](hs.keycodes.html#map) ), or a raw keycode number", + " * message - (optional) A string containing a message to be displayed via [hs.alert()](hs.alert.html) when the hotkey has been triggered; if omitted, no alert will be shown", + " * pressedfn - A function that will be called when the hotkey has been pressed, or nil", + " * releasedfn - A function that will be called when the hotkey has been released, or nil", + " * repeatfn - A function that will be called when a pressed hotkey is repeating, or nil" + ], + "parameters_gfm": "
    \n
  • mods - A table containing as elements the keyboard modifiers required, which should be one or more of the following:
      \n
    • "lCmd", "lCommand", or "l⌘" for the left Command modifier
    • \n
    • "rCmd", "rCommand", or "r⌘" for the right Command modifier
    • \n
    • "lCtrl", "lControl" or "l⌃" for the left Control modifier
    • \n
    • "rCtrl", "rControl" or "r⌃" for the right Control modifier
    • \n
    • "lAlt", "lOpt", "lOption" or "l⌥" for the left Option modifier
    • \n
    • "rAlt", "rOpt", "rOption" or "r⌥" for the right Option modifier
    • \n
    • "lShift" or "l⇧" for the left Shift modifier
    • \n
    • "rShift" or "r⇧" for the right Shift modifier
    • \n
    \n
  • \n
  • key - A string containing the name of a keyboard key (as found in hs.keycodes.map ), or a raw keycode number
  • \n
  • message - (optional) A string containing a message to be displayed via hs.alert() when the hotkey has been triggered; if omitted, no alert will be shown
  • \n
  • pressedfn - A function that will be called when the hotkey has been pressed, or nil
  • \n
  • releasedfn - A function that will be called when the hotkey has been released, or nil
  • \n
  • repeatfn - A function that will be called when a pressed hotkey is repeating, or nil
  • \n
\n", + "returns": [ + " * a new, initially disabled, hotkey with the specified left/right modifiers." + ], + "returns_gfm": "
    \n
  • a new, initially disabled, hotkey with the specified left/right modifiers.
  • \n
\n", + "signature": "LeftRightHotkey:new(mods, key, [message,] pressedfn, releasedfn, repeatfn) -> LeftRightHotkeyObject", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:start() -> self", + "def_gfm": "LeftRightHotkey:start() -> self", + "desc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "desc_gfm": "

Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

\n", + "doc": "Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this enables the use of hotkeys created by using this Spoon.", + "doc_gfm": "

Starts watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • the LeftRightHotkey spoon object
  • \n
\n

Notes:

\n
    \n
  • this enables the use of hotkeys created by using this Spoon.
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "444", + "name": "start", + "notes": [ + " * this enables the use of hotkeys created by using this Spoon." + ], + "notes_gfm": "
    \n
  • this enables the use of hotkeys created by using this Spoon.
  • \n
\n", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "returns_gfm": "
    \n
  • the LeftRightHotkey spoon object
  • \n
\n", + "signature": "LeftRightHotkey:start() -> self", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "LeftRightHotkey:stop() -> self", + "def_gfm": "LeftRightHotkey:stop() -> self", + "desc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.", + "desc_gfm": "

Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

\n", + "doc": "Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.\n\nParameters:\n * None\n\nReturns:\n * the LeftRightHotkey spoon object\n\nNotes:\n * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available.", + "doc_gfm": "

Stops watching for flag (modifier key) change events that can determine if the right or left modifiers have been pressed.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • the LeftRightHotkey spoon object
  • \n
\n

Notes:

\n
    \n
  • this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with hs.hotkey directly will still be available.
  • \n
\n", + "examples": [], + "file": "Source/LeftRightHotkey.spoon/init.lua", + "lineno": "471", + "name": "stop", + "notes": [ + " * this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with [hs.hotkey](hs.hotkey.html) directly will still be available." + ], + "notes_gfm": "
    \n
  • this will implicitly disable all hotkeys created by using this Spoon -- only those hotkeys which are defined with hs.hotkey directly will still be available.
  • \n
\n", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * the LeftRightHotkey spoon object" + ], + "returns_gfm": "
    \n
  • the LeftRightHotkey spoon object
  • \n
\n", + "signature": "LeftRightHotkey:stop() -> self", + "stripped_doc": "", + "type": "Method" + } + ], + "name": "LeftRightHotkey", + "stripped_doc": "\nThis is accomplished by creating unactivated hotkeys for each definition and using an [hs.eventtap](hs.eventtap.html) watcher to detect when modifier keys are pressed and conditionally activating only those hotkeys which correspond to the left or right modifiers currently active as specified by the `bind` and `new` methods of this spoon.\n\nThe `LeftRightHotkeyObject` that is returned by [LeftRightHotkey:new](#new) and [LeftRightHotkey:bind](#bind) supports the following methods in a manner similar to the [hs.hotkey](hs.hotkey.html) equivalents:\n\n * `LeftRightHotkeyObject:enable()` -- enables the registered hotkey.\n * `LeftRightHotkeyObject:disable()` -- disables the registered hotkey.\n * `LeftRightHotkeyObject:delete()` -- deletes the registered hotkey.\n * `LeftRightHotkeyObject:isEnabled() -- returns a boolean value specifying whether the hotkey is currently enabled (true) or disabled (false)\n\nThe following modifiers are recognized by this spoon in the modifier table when setting up hotkeys with this spoon:\n * \"lCmd\", \"lCommand\", or \"l⌘\" for the left Command modifier\n * \"rCmd\", \"rCommand\", or \"r⌘\" for the right Command modifier\n * \"lCtrl\", \"lControl\" or \"l⌃\" for the left Control modifier\n * \"rCtrl\", \"rControl\" or \"r⌃\" for the right Control modifier\n * \"lAlt\", \"lOpt\", \"lOption\" or \"l⌥\" for the left Option modifier\n * \"rAlt\", \"rOpt\", \"rOption\" or \"r⌥\" for the right Option modifier\n * \"lShift\" or \"l⇧\" for the left Shift modifier\n * \"rShift\" or \"r⇧\" for the right Shift modifier\n\nThe modifiers table for any given hotkey is all inclusive; this means that if you specify `{ \"rShift\", \"lShift\" }` then *both* the left and right shift keys *must* be pressed to trigger the hotkey -- if you want either/or, then stick with [hs.hotkey](hs.hotkey.html).\n\nAlternatively, if you want to setup a hotkey when *either* command key is pressed with *only* the right shift, you would need to set up two hotkeys with this spoon:\n e.g. `LeftRightHotkey:bind({ \"rCmd\", \"rShift\" }, \"a\", myFunction)` *and* `LeftRightHotkey:bind({ \"lCmd\", \"rShift\" }, \"a\", myFunction)`\n\nThis spoon works by using an eventtap to detect flag changes (modifier keys) and when they change, the appropriate hotkeys are enabled or disabled. This means that you should be aware of the following:\n * like all eventtaps, if the Hammerspoon application is particularly busy with some other task, it is possible for the flag change to be missed or for the macOS to disable the eventtap entirely.\n * behind the scenes, when a given set of flag changes occur that match a defined hotkey, the hotkey is actually enabled through `hs.hotkey:enable()` -- this means that in truth, either side's modifiers would trigger the callback. Under normal circumstances this won't be noticed because as soon as you switch to the alternate side's modifier, the flag change event will be detected and the hotkey will be disabled. However, as noted above, if Hammerspoon is particularly busy, it is possible for this event to be missed.\n * a timer runs (once this Spoon has been started the first time) which will check to see if the eventtap has been internally disabled and re-enable it if necessary; alternatively you can re-issue [LeftRightHotkey:start()](#start) to force the eventtap to be reset if necessary.\n * if your hotkeys seem out of sync, try pressing and releasing any modifier key -- this will reset the enabled/disabled hotkeys if a previous flag change was missed, but the eventtap is still running or has been reset by one of the methods described above.\n\nLike all Spoons, don't forget to use the [LeftRightHotkey:start()](#start) method to activate the modifier key watcher.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/LeftRightHotkey.spoon.zip)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], From 72339743156c43919e140de044d68128b4df4217 Mon Sep 17 00:00:00 2001 From: eks5115 Date: Wed, 7 Aug 2024 21:00:01 +0800 Subject: [PATCH 06/55] add InputSourceSwitch (#243) * add InputSourceSwitch * remove bin InputSourceSelector --- Source/InputSourceSwitch.spoon/init.lua | 113 ++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Source/InputSourceSwitch.spoon/init.lua diff --git a/Source/InputSourceSwitch.spoon/init.lua b/Source/InputSourceSwitch.spoon/init.lua new file mode 100644 index 00000000..d3814be4 --- /dev/null +++ b/Source/InputSourceSwitch.spoon/init.lua @@ -0,0 +1,113 @@ +--- === InputSourceSwitch === +--- +--- Automatically switch the input source when switching applications. +--- +--- Example: +--- ``` +--- hs.loadSpoon("InputSourceSwitch") +--- +--- spoon.InputSourceSwitch:setApplications({ +--- ["WeChat"] = "Pinyin - Simplified", +--- ["Mail"] = "ABC" +--- }) +--- +--- spoon.InputSourceSwitch:start() +--- ``` +--- +--- Download: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip) + +local obj = {} +obj.__index = obj + +-- Metadata +obj.name = "InputSourceSwitch" +obj.version = "1.0" +obj.author = "eks5115 " +obj.homepage = "https://github.com/Hammerspoon/Spoons" +obj.license = "MIT - https://opensource.org/licenses/MIT" + +local log = hs.logger.new('InputSourceSwitch','debug') +log.d('Init') + +-- Internal function used to get enabled input sources +local function isLayout(layoutName) + local layouts = hs.keycodes.layouts() + for key, value in pairs(layouts) do + if (value == layoutName) then + return true + end + end + + return false +end + +local function isMethod(methodName) + local methods = hs.keycodes.methods() + for key, value in pairs(methods) do + if (value == methodName) then + return true + end + end + + return false +end + +local function setAppInputSource(appName, sourceName, event) + event = event or hs.window.filter.windowFocused + + hs.window.filter.new(appName):subscribe(event, function() + local r = true + + if (isLayout(sourceName)) then + r = hs.keycodes.setLayout(sourceName) + elseif isMethod(sourceName) then + r = hs.keycodes.setMethod(sourceName) + else + hs.alert.show(string.format('sourceName: %s is not layout or method', sourceName)) + end + + if (not r) then + hs.alert.show(string.format('set %s to %s failure', appName, sourceName)) + end + end) +end + +--- InputSourceSwitch.applicationMap +--- Variable +--- Mapping the application name to the input source +obj.applicationsMap = {} + +--- InputSourceSwitch:setApplications() +--- Method +--- Set that mapping the application name to the input source +--- +--- Parameters: +--- * applications - A table containing that mapping the application name to the input source +--- key is the application name and value is the input source name +--- example: +--- ``` +--- { +--- ["WeChat"] = "Pinyin - Simplified", +--- ["Mail"] = "ABC" +--- } +--- ``` +function obj:setApplications(applications) + for key, value in pairs(applications) do + obj.applicationsMap[key] = value + end +end + +--- InputSourceSwitch:start() +--- Method +--- Start InputSourceSwitch +--- +--- Parameters: +--- * None +function obj:start() + for k,v in pairs(self.applicationsMap) do + setAppInputSource(k, v) + end + return self +end + +return obj From 0fe7488a816204ab52c9d762fa9f1cf12d45a6dc Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:00:19 +0000 Subject: [PATCH 07/55] Generate docs for InputSourceSwitch --- Source/InputSourceSwitch.spoon/docs.json | 112 +++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 Source/InputSourceSwitch.spoon/docs.json diff --git a/Source/InputSourceSwitch.spoon/docs.json b/Source/InputSourceSwitch.spoon/docs.json new file mode 100644 index 00000000..9c93877c --- /dev/null +++ b/Source/InputSourceSwitch.spoon/docs.json @@ -0,0 +1,112 @@ +[ + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "InputSourceSwitch:setApplications()", + "desc": "Set that mapping the application name to the input source", + "doc": "Set that mapping the application name to the input source\n\nParameters:\n * applications - A table containing that mapping the application name to the input source\n key is the application name and value is the input source name\n example:\n```\n{\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n}\n```", + "examples": [], + "file": "Source/InputSourceSwitch.spoon//init.lua", + "lineno": "80", + "name": "setApplications", + "notes": [], + "parameters": [ + " * applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: ``` { [\"WeChat\"] = \"Pinyin - Simplified\", [\"Mail\"] = \"ABC\" } ```" + ], + "returns": [], + "signature": "InputSourceSwitch:setApplications()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputSourceSwitch:start()", + "desc": "Start InputSourceSwitch", + "doc": "Start InputSourceSwitch\n\nParameters:\n * None", + "examples": [], + "file": "Source/InputSourceSwitch.spoon//init.lua", + "lineno": "100", + "name": "start", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "InputSourceSwitch:start()", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [ + { + "def": "InputSourceSwitch.applicationMap", + "desc": "Mapping the application name to the input source", + "doc": "Mapping the application name to the input source", + "file": "Source/InputSourceSwitch.spoon//init.lua", + "lineno": "75", + "name": "applicationMap", + "signature": "InputSourceSwitch.applicationMap", + "stripped_doc": "", + "type": "Variable" + } + ], + "desc": "Automatically switch the input source when switching applications.", + "doc": "Automatically switch the input source when switching applications.\n\nExample:\n```\nhs.loadSpoon(\"InputSourceSwitch\")\n\nspoon.InputSourceSwitch:setApplications({\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n})\n\nspoon.InputSourceSwitch:start()\n```\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip)", + "items": [ + { + "def": "InputSourceSwitch.applicationMap", + "desc": "Mapping the application name to the input source", + "doc": "Mapping the application name to the input source", + "file": "Source/InputSourceSwitch.spoon//init.lua", + "lineno": "75", + "name": "applicationMap", + "signature": "InputSourceSwitch.applicationMap", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "InputSourceSwitch:setApplications()", + "desc": "Set that mapping the application name to the input source", + "doc": "Set that mapping the application name to the input source\n\nParameters:\n * applications - A table containing that mapping the application name to the input source\n key is the application name and value is the input source name\n example:\n```\n{\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n}\n```", + "examples": [], + "file": "Source/InputSourceSwitch.spoon//init.lua", + "lineno": "80", + "name": "setApplications", + "notes": [], + "parameters": [ + " * applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: ``` { [\"WeChat\"] = \"Pinyin - Simplified\", [\"Mail\"] = \"ABC\" } ```" + ], + "returns": [], + "signature": "InputSourceSwitch:setApplications()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputSourceSwitch:start()", + "desc": "Start InputSourceSwitch", + "doc": "Start InputSourceSwitch\n\nParameters:\n * None", + "examples": [], + "file": "Source/InputSourceSwitch.spoon//init.lua", + "lineno": "100", + "name": "start", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "InputSourceSwitch:start()", + "stripped_doc": "", + "type": "Method" + } + ], + "name": "InputSourceSwitch", + "stripped_doc": "\nExample:\n```\nhs.loadSpoon(\"InputSourceSwitch\")\n\nspoon.InputSourceSwitch:setApplications({\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n})\n\nspoon.InputSourceSwitch:start()\n```\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip)", + "submodules": [], + "type": "Module" + } +] \ No newline at end of file From 48a1b774f3a70fc2e4544a83d914b2520fec52a3 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:00:19 +0000 Subject: [PATCH 08/55] Add binary package for InputSourceSwitch. --- Spoons/InputSourceSwitch.spoon.zip | Bin 0 -> 2227 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Spoons/InputSourceSwitch.spoon.zip diff --git a/Spoons/InputSourceSwitch.spoon.zip b/Spoons/InputSourceSwitch.spoon.zip new file mode 100644 index 0000000000000000000000000000000000000000..a01fe646520e5e2e1b9110fa117ae4539a86b265 GIT binary patch literal 2227 zcmaKt2{hDQAIJX;jd(_bFvh;L*~1u7F}7%s7#@UZgb_2uc%~P5ZFOj5mwg>t-Y{iG zMcLOJyM!=V%hFiFMByDz&v~BbJnvigo_o)|=brod-QPXu_x)Of;0CT)QG02ucypFwU`x`C@>#Z8-Paxpc>@Wub&=jH4bDBMfBtC$HYaRpuT;c4y z)@Xa?^Ii9x`}XFhd66nIrWsU8W|% zP=t)MjDg!9$MsJPE;C5u7;2Cj5{YCwX3=a;Uq+noAZf&1OC29)+hTKf6YQtL2CFWVQD`?i&`4nr5AJq5=I;F5P z(n-38E-~kNHn%=AlltnDNZnzCNJRU~&%HKpdRH26kOZ(5x4M9SowCk52@Y$y&nrl{o&zs*Ix#>?x;E(Jjc=y)n&XG>wkC zYUR$IP;7(=<=AD>RlyC>DZNZCVG7@e_H^WSn>|7O9Pb+k3fOv=mU)ef9# z;MCKql2j2chft_($-Q4SZ;BbV8hg2y5?nLYBlFe37uR`Jy?saJ6=qW6q?s%?C69B4TERy|c4y{IFO=p5=)u zNS@bf5W&6UrUnd}@;bQe!WPR#1HzZC5S0#7xRbgez}wUI?*Sle+PQvDTq3OOz&eTY zE59>%u^IV(EIzksL`tIh-phc33(kC5`b_Q^h~#ik0oY-#RQDE<)cbWyGN;PBURt;f z1e5IEEm$`R>J%=mpAzd@*b{%vr0moq45?q^>l~@bsIOqFy+F^{lbxwFXS3y5J(p@4 z*2tzw;?1-M!%{)B_P78A32IX{)?eH17iWTnh6tDx^-DboLmV1873W5$;1Fw_Ze#tk z`OG&BmWsYm!Gy`4w7v7@It61R%#JSR=Hp*5*-an8ORWRnL~K)xC-F;nxt`9N2Xj_y z?eP623i~qS7Mko%r&;gfwAe!u`)%Q|5n;&YMO z$q^wJz@x&$k4lqkkiGkHD04_@X(a783m&_P+;PhsJk@qo!9-^3ebk5Wx$Ml`RRQd? zO)NS8VG&ekHcUHj-A52EXa;d|ETOzk4CSwm#z1{xBsE!v0wyCF1M9zKkhx~FTgTu2 zxzyiJ?3?^ToarM)TUeJui6aAm(7H>AxUS4;p$R^^#loPe0a*j}80v(6`9#0IITvnp z5s;sq@85E3)f-VS-K6BqpLIj2E;{ms6I`jah?VgMRYXzYYkJ~fRN^N|Lsvn* z9*bFF!FOA5A#F7z)?#3On`}ryY!iRGGB1&T@yo++eH_m#s>fxC+jt8D!sph@ScWR1mLX?TZ zH#7XsCS=B5KT;|WZVc#GwrjkQlMX(y{aNGm`)eU}j9H*O*=)tRt9RD@_A&YXQt38i z^3w&y^L7H^P!o62D1ui0!&vmmJACd-wGU2Q($(BPu`%=IAbIFr6gsjo2)nlzA6B8a zT~l25=M;XwxUM@`JQ4yP-`QLqCzMtz4$?+*67{~E>1?Re$@<1=jppE#0{zHyVSl(U z6!?VNU;fyExxYK`KRog~{YU=$ozB7LQX*`ALjTK+*-`f0_$N{Rx1j$X#f$65IsC1> Wf0PXOf&EVavAYuc)z`uMyZ-`Io6=?g literal 0 HcmV?d00001 From c43cdecbd183adf31180bbdc0811dc046222d678 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:00:19 +0000 Subject: [PATCH 09/55] Update docs --- docs/EmmyLua.html | 6 +- docs/InputSourceSwitch.html | 140 +++++++++++++++++++++++++++++++++++ docs/docs.json | 110 +++++++++++++++++++++++++++ docs/docs_index.json | 23 ++++++ docs/index.html | 5 ++ docs/templated_docs.json | 144 +++++++++++++++++++++++++++++++++++- 6 files changed, 424 insertions(+), 4 deletions(-) create mode 100644 docs/InputSourceSwitch.html diff --git a/docs/EmmyLua.html b/docs/EmmyLua.html index bf87fb03..b9c739f8 100644 --- a/docs/EmmyLua.html +++ b/docs/EmmyLua.html @@ -26,9 +26,9 @@

docs » EmmyLua

To start using this annotations library, add the annotations folder to your workspace. for lua-languag-server:

-
{
-  "Lua.workspace.library": ["/Users/YOUR_USERNAME/.hammerspoon/Spoons/EmmyLua.spoon/annotations"]
-}
+
{
+  "Lua.workspace.library": ["/Users/YOUR_USERNAME/.hammerspoon/Spoons/EmmyLua.spoon/annotations"]
+}
 

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/EmmyLua.spoon.zip

diff --git a/docs/InputSourceSwitch.html b/docs/InputSourceSwitch.html new file mode 100644 index 00000000..944295c9 --- /dev/null +++ b/docs/InputSourceSwitch.html @@ -0,0 +1,140 @@ + + + + Hammerspoon docs: InputSourceSwitch + + + + +
+

docs » InputSourceSwitch

+

Automatically switch the input source when switching applications.

+

Example:

+ +
hs.loadSpoon("InputSourceSwitch")
+
+spoon.InputSourceSwitch:setApplications({
+    ["WeChat"] = "Pinyin - Simplified",
+    ["Mail"] = "ABC"
+})
+
+spoon.InputSourceSwitch:start()
+
+

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip

+ +
+

API Overview

+
    +
  • Variables - Configurable values
  • + +
  • Methods - API calls which can only be made on an object returned by a constructor
  • + +
+

API Documentation

+

Variables

+
+ +
applicationMap
+ + + + + + + + + + + + + + + + + +
SignatureInputSourceSwitch.applicationMap
TypeVariable
Description

Mapping the application name to the input source

+
SourceSource/InputSourceSwitch.spoon/init.lua line 75
+
+

Methods

+
+ +
setApplications
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureInputSourceSwitch:setApplications()
TypeMethod
Description

Set that mapping the application name to the input source

+
Parameters
    +
  • applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: { ["WeChat"] = "Pinyin - Simplified", ["Mail"] = "ABC" }
  • +
+
Returns
SourceSource/InputSourceSwitch.spoon/init.lua line 80
+
+
+ +
start
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureInputSourceSwitch:start()
TypeMethod
Description

Start InputSourceSwitch

+
Parameters
    +
  • None
  • +
+
Returns
SourceSource/InputSourceSwitch.spoon/init.lua line 100
+
+ + \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index e3f8d4c5..1253f297 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -6765,6 +6765,116 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "InputSourceSwitch:setApplications()", + "desc": "Set that mapping the application name to the input source", + "doc": "Set that mapping the application name to the input source\n\nParameters:\n * applications - A table containing that mapping the application name to the input source\n key is the application name and value is the input source name\n example:\n```\n{\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n}\n```", + "examples": [], + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "80", + "name": "setApplications", + "notes": [], + "parameters": [ + " * applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: ``` { [\"WeChat\"] = \"Pinyin - Simplified\", [\"Mail\"] = \"ABC\" } ```" + ], + "returns": [], + "signature": "InputSourceSwitch:setApplications()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputSourceSwitch:start()", + "desc": "Start InputSourceSwitch", + "doc": "Start InputSourceSwitch\n\nParameters:\n * None", + "examples": [], + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "100", + "name": "start", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "InputSourceSwitch:start()", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [ + { + "def": "InputSourceSwitch.applicationMap", + "desc": "Mapping the application name to the input source", + "doc": "Mapping the application name to the input source", + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "75", + "name": "applicationMap", + "signature": "InputSourceSwitch.applicationMap", + "stripped_doc": "", + "type": "Variable" + } + ], + "desc": "Automatically switch the input source when switching applications.", + "doc": "Automatically switch the input source when switching applications.\n\nExample:\n```\nhs.loadSpoon(\"InputSourceSwitch\")\n\nspoon.InputSourceSwitch:setApplications({\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n})\n\nspoon.InputSourceSwitch:start()\n```\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip)", + "items": [ + { + "def": "InputSourceSwitch.applicationMap", + "desc": "Mapping the application name to the input source", + "doc": "Mapping the application name to the input source", + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "75", + "name": "applicationMap", + "signature": "InputSourceSwitch.applicationMap", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "InputSourceSwitch:setApplications()", + "desc": "Set that mapping the application name to the input source", + "doc": "Set that mapping the application name to the input source\n\nParameters:\n * applications - A table containing that mapping the application name to the input source\n key is the application name and value is the input source name\n example:\n```\n{\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n}\n```", + "examples": [], + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "80", + "name": "setApplications", + "notes": [], + "parameters": [ + " * applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: ``` { [\"WeChat\"] = \"Pinyin - Simplified\", [\"Mail\"] = \"ABC\" } ```" + ], + "returns": [], + "signature": "InputSourceSwitch:setApplications()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputSourceSwitch:start()", + "desc": "Start InputSourceSwitch", + "doc": "Start InputSourceSwitch\n\nParameters:\n * None", + "examples": [], + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "100", + "name": "start", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "InputSourceSwitch:start()", + "stripped_doc": "", + "type": "Method" + } + ], + "name": "InputSourceSwitch", + "stripped_doc": "\nExample:\n```\nhs.loadSpoon(\"InputSourceSwitch\")\n\nspoon.InputSourceSwitch:setApplications({\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n})\n\nspoon.InputSourceSwitch:start()\n```\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], diff --git a/docs/docs_index.json b/docs/docs_index.json index 169bce42..08451252 100644 --- a/docs/docs_index.json +++ b/docs/docs_index.json @@ -1285,6 +1285,29 @@ "name": "show", "type": "Method" }, + { + "desc": "Automatically switch the input source when switching applications.", + "name": "InputSourceSwitch", + "type": "Module" + }, + { + "desc": "Mapping the application name to the input source", + "module": "InputSourceSwitch", + "name": "applicationMap", + "type": "Variable" + }, + { + "desc": "Set that mapping the application name to the input source", + "module": "InputSourceSwitch", + "name": "setApplications", + "type": "Method" + }, + { + "desc": "Start InputSourceSwitch", + "module": "InputSourceSwitch", + "name": "start", + "type": "Method" + }, { "desc": "Get and Add items from Keychain. Provides no hotkeys and maintains no state", "name": "Keychain", diff --git a/docs/index.html b/docs/index.html index e6221855..a552c5cb 100644 --- a/docs/index.html +++ b/docs/index.html @@ -237,6 +237,11 @@

API documentation

HSKeybindings

Display Keybindings registered with bindHotkeys() and Spoons

+ + + + InputSourceSwitch +

Automatically switch the input source when switching applications.

diff --git a/docs/templated_docs.json b/docs/templated_docs.json index b8240850..bf8baf73 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -5817,7 +5817,7 @@ "desc": "Thie plugin generates EmmyLua annotations for Hammerspoon and any installed Spoons", "desc_gfm": "

Thie plugin generates EmmyLua annotations for Hammerspoon and any installed Spoons

\n", "doc": "Thie plugin generates EmmyLua annotations for Hammerspoon and any installed Spoons\nunder ~/.hammerspoon/Spoons/EmmyLua.spoon/annotations.\nAnnotations will only be generated if they don't exist yet or are out of date.\n\nNote: Load this Spoon before any pathwatchers are defined to avoid unintended behaviour (for example multiple reloads when the annotions are created).\n\nIn order to get auto completion in your editor, you need to have one of the following LSP servers properly configured:\n* [lua-language-server](https://github.com/sumneko/lua-language-server) (recommended)\n* [EmmyLua-LanguageServer](https://github.com/EmmyLua/EmmyLua-LanguageServer)\n\nTo start using this annotations library, add the annotations folder to your workspace.\nfor lua-languag-server:\n\n```json\n{\n \"Lua.workspace.library\": [\"/Users/YOUR_USERNAME/.hammerspoon/Spoons/EmmyLua.spoon/annotations\"]\n}\n```\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/EmmyLua.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/EmmyLua.spoon.zip)", - "doc_gfm": "

Thie plugin generates EmmyLua annotations for Hammerspoon and any installed Spoons\nunder ~/.hammerspoon/Spoons/EmmyLua.spoon/annotations.\nAnnotations will only be generated if they don't exist yet or are out of date.

\n

Note: Load this Spoon before any pathwatchers are defined to avoid unintended behaviour (for example multiple reloads when the annotions are created).

\n

In order to get auto completion in your editor, you need to have one of the following LSP servers properly configured:

\n\n

To start using this annotations library, add the annotations folder to your workspace.\nfor lua-languag-server:

\n
{\n  "Lua.workspace.library": ["/Users/YOUR_USERNAME/.hammerspoon/Spoons/EmmyLua.spoon/annotations"]\n}\n
\n

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/EmmyLua.spoon.zip

\n", + "doc_gfm": "

Thie plugin generates EmmyLua annotations for Hammerspoon and any installed Spoons\nunder ~/.hammerspoon/Spoons/EmmyLua.spoon/annotations.\nAnnotations will only be generated if they don't exist yet or are out of date.

\n

Note: Load this Spoon before any pathwatchers are defined to avoid unintended behaviour (for example multiple reloads when the annotions are created).

\n

In order to get auto completion in your editor, you need to have one of the following LSP servers properly configured:

\n\n

To start using this annotations library, add the annotations folder to your workspace.\nfor lua-languag-server:

\n
{\n  "Lua.workspace.library": ["/Users/YOUR_USERNAME/.hammerspoon/Spoons/EmmyLua.spoon/annotations"]\n}\n
\n

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/EmmyLua.spoon.zip

\n", "items": [], "name": "EmmyLua", "stripped_doc": "under ~/.hammerspoon/Spoons/EmmyLua.spoon/annotations.\nAnnotations will only be generated if they don't exist yet or are out of date.\n\nNote: Load this Spoon before any pathwatchers are defined to avoid unintended behaviour (for example multiple reloads when the annotions are created).\n\nIn order to get auto completion in your editor, you need to have one of the following LSP servers properly configured:\n* [lua-language-server](https://github.com/sumneko/lua-language-server) (recommended)\n* [EmmyLua-LanguageServer](https://github.com/EmmyLua/EmmyLua-LanguageServer)\n\nTo start using this annotations library, add the annotations folder to your workspace.\nfor lua-languag-server:\n\n```json\n{\n \"Lua.workspace.library\": [\"/Users/YOUR_USERNAME/.hammerspoon/Spoons/EmmyLua.spoon/annotations\"]\n}\n```\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/EmmyLua.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/EmmyLua.spoon.zip)", @@ -8633,6 +8633,148 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "InputSourceSwitch:setApplications()", + "def_gfm": "InputSourceSwitch:setApplications()", + "desc": "Set that mapping the application name to the input source", + "desc_gfm": "

Set that mapping the application name to the input source

\n", + "doc": "Set that mapping the application name to the input source\n\nParameters:\n * applications - A table containing that mapping the application name to the input source\n key is the application name and value is the input source name\n example:\n```\n{\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n}\n```", + "doc_gfm": "

Set that mapping the application name to the input source

\n

Parameters:

\n
    \n
  • applications - A table containing that mapping the application name to the input source\n key is the application name and value is the input source name\n example:
  • \n
\n\n
{\n    ["WeChat"] = "Pinyin - Simplified",\n    ["Mail"] = "ABC"\n}\n
\n", + "examples": [], + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "80", + "name": "setApplications", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: ``` { [\"WeChat\"] = \"Pinyin - Simplified\", [\"Mail\"] = \"ABC\" } ```" + ], + "parameters_gfm": "
    \n
  • applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: { ["WeChat"] = "Pinyin - Simplified", ["Mail"] = "ABC" }
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "InputSourceSwitch:setApplications()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputSourceSwitch:start()", + "def_gfm": "InputSourceSwitch:start()", + "desc": "Start InputSourceSwitch", + "desc_gfm": "

Start InputSourceSwitch

\n", + "doc": "Start InputSourceSwitch\n\nParameters:\n * None", + "doc_gfm": "

Start InputSourceSwitch

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "100", + "name": "start", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "InputSourceSwitch:start()", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [ + { + "def": "InputSourceSwitch.applicationMap", + "def_gfm": "InputSourceSwitch.applicationMap", + "desc": "Mapping the application name to the input source", + "desc_gfm": "

Mapping the application name to the input source

\n", + "doc": "Mapping the application name to the input source", + "doc_gfm": "

Mapping the application name to the input source

\n", + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "75", + "name": "applicationMap", + "signature": "InputSourceSwitch.applicationMap", + "stripped_doc": "", + "type": "Variable" + } + ], + "desc": "Automatically switch the input source when switching applications.", + "desc_gfm": "

Automatically switch the input source when switching applications.

\n", + "doc": "Automatically switch the input source when switching applications.\n\nExample:\n```\nhs.loadSpoon(\"InputSourceSwitch\")\n\nspoon.InputSourceSwitch:setApplications({\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n})\n\nspoon.InputSourceSwitch:start()\n```\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip)", + "doc_gfm": "

Automatically switch the input source when switching applications.

\n

Example:

\n\n
hs.loadSpoon("InputSourceSwitch")\n\nspoon.InputSourceSwitch:setApplications({\n    ["WeChat"] = "Pinyin - Simplified",\n    ["Mail"] = "ABC"\n})\n\nspoon.InputSourceSwitch:start()\n
\n

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip

\n", + "items": [ + { + "def": "InputSourceSwitch.applicationMap", + "def_gfm": "InputSourceSwitch.applicationMap", + "desc": "Mapping the application name to the input source", + "desc_gfm": "

Mapping the application name to the input source

\n", + "doc": "Mapping the application name to the input source", + "doc_gfm": "

Mapping the application name to the input source

\n", + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "75", + "name": "applicationMap", + "signature": "InputSourceSwitch.applicationMap", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "InputSourceSwitch:setApplications()", + "def_gfm": "InputSourceSwitch:setApplications()", + "desc": "Set that mapping the application name to the input source", + "desc_gfm": "

Set that mapping the application name to the input source

\n", + "doc": "Set that mapping the application name to the input source\n\nParameters:\n * applications - A table containing that mapping the application name to the input source\n key is the application name and value is the input source name\n example:\n```\n{\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n}\n```", + "doc_gfm": "

Set that mapping the application name to the input source

\n

Parameters:

\n
    \n
  • applications - A table containing that mapping the application name to the input source\n key is the application name and value is the input source name\n example:
  • \n
\n\n
{\n    ["WeChat"] = "Pinyin - Simplified",\n    ["Mail"] = "ABC"\n}\n
\n", + "examples": [], + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "80", + "name": "setApplications", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: ``` { [\"WeChat\"] = \"Pinyin - Simplified\", [\"Mail\"] = \"ABC\" } ```" + ], + "parameters_gfm": "
    \n
  • applications - A table containing that mapping the application name to the input source key is the application name and value is the input source name example: { ["WeChat"] = "Pinyin - Simplified", ["Mail"] = "ABC" }
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "InputSourceSwitch:setApplications()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputSourceSwitch:start()", + "def_gfm": "InputSourceSwitch:start()", + "desc": "Start InputSourceSwitch", + "desc_gfm": "

Start InputSourceSwitch

\n", + "doc": "Start InputSourceSwitch\n\nParameters:\n * None", + "doc_gfm": "

Start InputSourceSwitch

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/InputSourceSwitch.spoon/init.lua", + "lineno": "100", + "name": "start", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "InputSourceSwitch:start()", + "stripped_doc": "", + "type": "Method" + } + ], + "name": "InputSourceSwitch", + "stripped_doc": "\nExample:\n```\nhs.loadSpoon(\"InputSourceSwitch\")\n\nspoon.InputSourceSwitch:setApplications({\n [\"WeChat\"] = \"Pinyin - Simplified\",\n [\"Mail\"] = \"ABC\"\n})\n\nspoon.InputSourceSwitch:start()\n```\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/InputSourceSwitch.spoon.zip)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], From d5f5890f98a34dd931cc2c5363dc7e02cc80bc79 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 7 Aug 2024 14:04:18 +0100 Subject: [PATCH 10/55] Update workflows to not use deprecated action versions --- .github/workflows/PR.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index a8b1f939..e5ab8f93 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -25,10 +25,10 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Check-out the Spoons PR - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Check-out the Hammerspoon repository we need for doc building - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: repository: 'Hammerspoon/hammerspoon' path: 'hammerspoon' @@ -40,7 +40,7 @@ jobs: /usr/bin/python3 -m pip install -r requirements.txt # Find files modified by this PR - - uses: lots0logs/gh-action-get-changed-files@2.1.4 + - uses: lots0logs/gh-action-get-changed-files@2.2.2 with: token: ${{ secrets.GITHUB_TOKEN }} From da351bc111d2482e2174e83e504edef36131d8d0 Mon Sep 17 00:00:00 2001 From: dmgerman Date: Wed, 7 Aug 2024 06:07:02 -0700 Subject: [PATCH 11/55] Implemented customization of the size of the cheatsheet and order of items in it (#253) Co-authored-by: Daniel M German --- Source/ModalMgr.spoon/init.lua | 117 +++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 36 deletions(-) diff --git a/Source/ModalMgr.spoon/init.lua b/Source/ModalMgr.spoon/init.lua index 22916c1f..f62d4656 100644 --- a/Source/ModalMgr.spoon/init.lua +++ b/Source/ModalMgr.spoon/init.lua @@ -20,6 +20,17 @@ obj.modal_list = {} obj.active_list = {} obj.supervisor = nil +-- customize width and height of Cheatsheet +obj.width_factor = 0.30 +obj.height_factor = 0.30 +-- minimum sizes +obj.min_width = 200 +obj.min_height = 200 + +-- alighment for right column +obj.alignmentRightColumn = 'right' +obj.fillByRow = false + function obj:init() hsupervisor_keys = hsupervisor_keys or {{"cmd", "shift", "ctrl"}, "Q"} obj.supervisor = hs.hotkey.modal.new(hsupervisor_keys[1], hsupervisor_keys[2], 'Initialize Modal Environment') @@ -54,6 +65,64 @@ function obj:new(id) obj.modal_list[id] = hs.hotkey.modal.new() end + +-- this function draws the text on the window +-- +-- by default, it fills by row +-- but it can be customized to fill by column +function insertIntoSheet(position, st, row, column, n) + local textAlign = "left" + local xpos + local ypos + -- height available for one item, in percentage + -- add one for a small margin of at least 1/2 element at the bottom + local h = 100 / (math.ceil(n*1.0/2) + 1) + local w = "47%" + local xposLeft = "3%" + local xposRight = "50%" + if obj.fillByRow then + if position %2 == 1 then + xpos = xposLeft + ypos = tostring(math.floor(h * position / 2)) .. "%" + else + -- this one goes to the right + textAlign = obj.alignmentRigthColumn + xpos = xposRight + ypos = tostring(math.floor(h * (position-1) / 2)) .. "%" + end + else + local actualPos + if position > math.ceil(n / 2) then + -- this one goes to the right + textAlign = obj.alignmentRightColumn + xpos = xposRight + actualPos = position - math.ceil(n*1.0/2) + else + xpos = xposLeft + actualPos = position + end + ypos = tostring(math.floor(actualPos * h)) .. "%" + end + +-- print(ypos, n, h) + obj.which_key[position + 1] = { + type = "text", + text = st, + textFont = "Courier-Bold", + textSize = 16, + textColor = {hex = "#2390FF", alpha = 1}, + textAlignment = textAlign, + frame = { + x = xpos, + y = ypos, + -- w = tostring((1 - 80 / (cres.w / 5 * 3)) / 2), + w = w, + h = tostring(math.floor(h)) .. "%" + } + } + +end + --- ModalMgr:toggleCheatsheet([idList], [force]) --- Method --- Toggle the cheatsheet display of current modal environments's keybindings. @@ -68,11 +137,14 @@ function obj:toggleCheatsheet(iterList, force) else local cscreen = hs.screen.mainScreen() local cres = cscreen:fullFrame() + + local framew = math.max(math.floor(cres.w * obj.width_factor),obj.min_width) + local frameh = math.max(math.floor(cres.h * obj.height_factor), obj.min_height) obj.which_key:frame({ - x = cres.x + cres.w / 5, - y = cres.y + cres.h / 5, - w = cres.w / 5 * 3, - h = cres.h / 5 * 3 + w = framew, + h = frameh, + x = cres.x + (cres.w - framew) /2, + y = cres.y + (cres.h - frameh) /2 }) local keys_pool = {} local tmplist = iterList or obj.active_list @@ -89,38 +161,11 @@ function obj:toggleCheatsheet(iterList, force) end end end - for idx, val in ipairs(keys_pool) do - if idx % 2 == 1 then - obj.which_key[idx + 1] = { - type = "text", - text = keys_pool[idx], - textFont = "Courier-Bold", - textSize = 16, - textColor = {hex = "#2390FF", alpha = 1}, - textAlignment = "left", - frame = { - x = tostring(40 / (cres.w / 5 * 3)), - y = tostring((30 + (idx - math.ceil(idx / 2)) * math.ceil((cres.h / 5 * 3 - 60) / #keys_pool) * 2) / (cres.h / 5 * 3)), - w = tostring((1 - 80 / (cres.w / 5 * 3)) / 2), - h = tostring(math.ceil((cres.h / 5 * 3 - 60) / #keys_pool) * 2 / (cres.h / 5 * 3)) - } - } - else - obj.which_key[idx + 1] = { - type = "text", - text = keys_pool[idx], - textFont = "Courier-Bold", - textSize = 16, - textColor = {hex = "#2390FF"}, - textAlignment = "right", - frame = { - x = "50%", - y = tostring((30 + (idx - math.ceil(idx / 2) - 1) * math.ceil((cres.h / 5 * 3 - 60) / #keys_pool) * 2) / (cres.h / 5 * 3)), - w = tostring((1 - 80 / (cres.w / 5 * 3)) / 2), - h = tostring(math.ceil((cres.h / 5 * 3 - 60) / #keys_pool) * 2 / (cres.h / 5 * 3)) - } - } - end + -- if obj.orderByColumn then + if true then + for idx, val in ipairs(keys_pool) do + insertIntoSheet(idx,val, idx, 0, #keys_pool) + end end obj.which_key:show() end From a3ea0fcef758cb8e21dd3f9d87392bd0383dbe9a Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:07:25 +0000 Subject: [PATCH 12/55] Generate docs for ModalMgr --- Source/ModalMgr.spoon/docs.json | 60 +++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/Source/ModalMgr.spoon/docs.json b/Source/ModalMgr.spoon/docs.json index f6b505bb..b762d345 100644 --- a/Source/ModalMgr.spoon/docs.json +++ b/Source/ModalMgr.spoon/docs.json @@ -11,12 +11,17 @@ "def": "ModalMgr:activate(idList, [trayColor], [showKeys])", "desc": "Activate all modal environment in `idList`.", "doc": "Activate all modal environment in `idList`.\n\nParameters:\n * idList - An table specifying IDs of modal environments\n * trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to `nil`.\n * showKeys - A optional boolean value to show all available keybindings, defaults to `nil`.", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "174", "name": "activate", + "notes": [], "parameters": [ " * idList - An table specifying IDs of modal environments", " * trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to `nil`.", " * showKeys - A optional boolean value to show all available keybindings, defaults to `nil`." ], + "returns": [], "signature": "ModalMgr:activate(idList, [trayColor], [showKeys])", "stripped_doc": "", "type": "Method" @@ -25,10 +30,15 @@ "def": "ModalMgr:deactivate(idList)", "desc": "Deactivate modal environments in `idList`.", "doc": "Deactivate modal environments in `idList`.\n\nParameters:\n * idList - An table specifying IDs of modal environments", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "205", "name": "deactivate", + "notes": [], "parameters": [ " * idList - An table specifying IDs of modal environments" ], + "returns": [], "signature": "ModalMgr:deactivate(idList)", "stripped_doc": "", "type": "Method" @@ -36,8 +46,16 @@ { "def": "ModalMgr:deactivateAll()", "desc": "Deactivate all active modal environments.", - "doc": "Deactivate all active modal environments.\n", + "doc": "Deactivate all active modal environments.\n\nParameters:\n * None", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "224", "name": "deactivateAll", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], "signature": "ModalMgr:deactivateAll()", "stripped_doc": "", "type": "Method" @@ -46,10 +64,15 @@ "def": "ModalMgr:new(id)", "desc": "Create a new modal keybindings environment", "doc": "Create a new modal keybindings environment\n\nParameters:\n * id - A string specifying ID of new modal keybindings", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "57", "name": "new", + "notes": [], "parameters": [ " * id - A string specifying ID of new modal keybindings" ], + "returns": [], "signature": "ModalMgr:new(id)", "stripped_doc": "", "type": "Method" @@ -58,11 +81,16 @@ "def": "ModalMgr:toggleCheatsheet([idList], [force])", "desc": "Toggle the cheatsheet display of current modal environments's keybindings.", "doc": "Toggle the cheatsheet display of current modal environments's keybindings.\n\nParameters:\n * iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.\n * force - A optional boolean value to force show cheatsheet, defaults to `nil` (automatically).", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "126", "name": "toggleCheatsheet", + "notes": [], "parameters": [ " * iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.", " * force - A optional boolean value to force show cheatsheet, defaults to `nil` (automatically)." ], + "returns": [], "signature": "ModalMgr:toggleCheatsheet([idList], [force])", "stripped_doc": "", "type": "Method" @@ -76,12 +104,17 @@ "def": "ModalMgr:activate(idList, [trayColor], [showKeys])", "desc": "Activate all modal environment in `idList`.", "doc": "Activate all modal environment in `idList`.\n\nParameters:\n * idList - An table specifying IDs of modal environments\n * trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to `nil`.\n * showKeys - A optional boolean value to show all available keybindings, defaults to `nil`.", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "174", "name": "activate", + "notes": [], "parameters": [ " * idList - An table specifying IDs of modal environments", " * trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to `nil`.", " * showKeys - A optional boolean value to show all available keybindings, defaults to `nil`." ], + "returns": [], "signature": "ModalMgr:activate(idList, [trayColor], [showKeys])", "stripped_doc": "", "type": "Method" @@ -90,10 +123,15 @@ "def": "ModalMgr:deactivate(idList)", "desc": "Deactivate modal environments in `idList`.", "doc": "Deactivate modal environments in `idList`.\n\nParameters:\n * idList - An table specifying IDs of modal environments", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "205", "name": "deactivate", + "notes": [], "parameters": [ " * idList - An table specifying IDs of modal environments" ], + "returns": [], "signature": "ModalMgr:deactivate(idList)", "stripped_doc": "", "type": "Method" @@ -101,8 +139,16 @@ { "def": "ModalMgr:deactivateAll()", "desc": "Deactivate all active modal environments.", - "doc": "Deactivate all active modal environments.\n", + "doc": "Deactivate all active modal environments.\n\nParameters:\n * None", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "224", "name": "deactivateAll", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], "signature": "ModalMgr:deactivateAll()", "stripped_doc": "", "type": "Method" @@ -111,10 +157,15 @@ "def": "ModalMgr:new(id)", "desc": "Create a new modal keybindings environment", "doc": "Create a new modal keybindings environment\n\nParameters:\n * id - A string specifying ID of new modal keybindings", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "57", "name": "new", + "notes": [], "parameters": [ " * id - A string specifying ID of new modal keybindings" ], + "returns": [], "signature": "ModalMgr:new(id)", "stripped_doc": "", "type": "Method" @@ -123,11 +174,16 @@ "def": "ModalMgr:toggleCheatsheet([idList], [force])", "desc": "Toggle the cheatsheet display of current modal environments's keybindings.", "doc": "Toggle the cheatsheet display of current modal environments's keybindings.\n\nParameters:\n * iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.\n * force - A optional boolean value to force show cheatsheet, defaults to `nil` (automatically).", + "examples": [], + "file": "Source/ModalMgr.spoon//init.lua", + "lineno": "126", "name": "toggleCheatsheet", + "notes": [], "parameters": [ " * iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.", " * force - A optional boolean value to force show cheatsheet, defaults to `nil` (automatically)." ], + "returns": [], "signature": "ModalMgr:toggleCheatsheet([idList], [force])", "stripped_doc": "", "type": "Method" From 3ba40b859ab0457db53d85c1989f2cbc9cfada94 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:07:25 +0000 Subject: [PATCH 13/55] Add binary package for ModalMgr. --- Spoons/ModalMgr.spoon.zip | Bin 3144 -> 3748 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Spoons/ModalMgr.spoon.zip b/Spoons/ModalMgr.spoon.zip index 18b12c77c763c6f0f4e0912ffca7cbedf2997930..7a95b4fdc30538d9cb5272ed9712620c46ba61ca 100644 GIT binary patch literal 3748 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 QDfs7L{n_IK=3ig`0%-}$00000 literal 3144 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 From c05e8138156fd4de7c67d30e3bd56979ca3142d9 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:07:26 +0000 Subject: [PATCH 14/55] Update docs --- docs/ModalMgr.html | 10 +++++----- docs/docs.json | 20 ++++++++++---------- docs/templated_docs.json | 20 ++++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/ModalMgr.html b/docs/ModalMgr.html index d1a405dc..b16b53a1 100644 --- a/docs/ModalMgr.html +++ b/docs/ModalMgr.html @@ -64,7 +64,7 @@
activate
Source - Source/ModalMgr.spoon/init.lua line 129 + Source/ModalMgr.spoon/init.lua line 174 @@ -98,7 +98,7 @@
deactivate
Source - Source/ModalMgr.spoon/init.lua line 160 + Source/ModalMgr.spoon/init.lua line 205 @@ -132,7 +132,7 @@
deactivateAll
Source - Source/ModalMgr.spoon/init.lua line 179 + Source/ModalMgr.spoon/init.lua line 224 @@ -166,7 +166,7 @@
new
Source - Source/ModalMgr.spoon/init.lua line 46 + Source/ModalMgr.spoon/init.lua line 57 @@ -201,7 +201,7 @@
toggleCheatsheet
Source - Source/ModalMgr.spoon/init.lua line 57 + Source/ModalMgr.spoon/init.lua line 126 diff --git a/docs/docs.json b/docs/docs.json index 1253f297..5bd5b07f 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -8759,7 +8759,7 @@ "doc": "Activate all modal environment in `idList`.\n\nParameters:\n * idList - An table specifying IDs of modal environments\n * trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to `nil`.\n * showKeys - A optional boolean value to show all available keybindings, defaults to `nil`.", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "129", + "lineno": "174", "name": "activate", "notes": [], "parameters": [ @@ -8778,7 +8778,7 @@ "doc": "Deactivate modal environments in `idList`.\n\nParameters:\n * idList - An table specifying IDs of modal environments", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "160", + "lineno": "205", "name": "deactivate", "notes": [], "parameters": [ @@ -8795,7 +8795,7 @@ "doc": "Deactivate all active modal environments.\n\nParameters:\n * None", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "179", + "lineno": "224", "name": "deactivateAll", "notes": [], "parameters": [ @@ -8812,7 +8812,7 @@ "doc": "Create a new modal keybindings environment\n\nParameters:\n * id - A string specifying ID of new modal keybindings", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "46", + "lineno": "57", "name": "new", "notes": [], "parameters": [ @@ -8829,7 +8829,7 @@ "doc": "Toggle the cheatsheet display of current modal environments's keybindings.\n\nParameters:\n * iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.\n * force - A optional boolean value to force show cheatsheet, defaults to `nil` (automatically).", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "57", + "lineno": "126", "name": "toggleCheatsheet", "notes": [], "parameters": [ @@ -8852,7 +8852,7 @@ "doc": "Activate all modal environment in `idList`.\n\nParameters:\n * idList - An table specifying IDs of modal environments\n * trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to `nil`.\n * showKeys - A optional boolean value to show all available keybindings, defaults to `nil`.", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "129", + "lineno": "174", "name": "activate", "notes": [], "parameters": [ @@ -8871,7 +8871,7 @@ "doc": "Deactivate modal environments in `idList`.\n\nParameters:\n * idList - An table specifying IDs of modal environments", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "160", + "lineno": "205", "name": "deactivate", "notes": [], "parameters": [ @@ -8888,7 +8888,7 @@ "doc": "Deactivate all active modal environments.\n\nParameters:\n * None", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "179", + "lineno": "224", "name": "deactivateAll", "notes": [], "parameters": [ @@ -8905,7 +8905,7 @@ "doc": "Create a new modal keybindings environment\n\nParameters:\n * id - A string specifying ID of new modal keybindings", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "46", + "lineno": "57", "name": "new", "notes": [], "parameters": [ @@ -8922,7 +8922,7 @@ "doc": "Toggle the cheatsheet display of current modal environments's keybindings.\n\nParameters:\n * iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.\n * force - A optional boolean value to force show cheatsheet, defaults to `nil` (automatically).", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "57", + "lineno": "126", "name": "toggleCheatsheet", "notes": [], "parameters": [ diff --git a/docs/templated_docs.json b/docs/templated_docs.json index bf8baf73..5b04d20b 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -11164,7 +11164,7 @@ "doc_gfm": "

Activate all modal environment in idList.

\n

Parameters:

\n
    \n
  • idList - An table specifying IDs of modal environments
  • \n
  • trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to nil.
  • \n
  • showKeys - A optional boolean value to show all available keybindings, defaults to nil.
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "129", + "lineno": "174", "name": "activate", "notes": [], "notes_gfm": "", @@ -11189,7 +11189,7 @@ "doc_gfm": "

Deactivate modal environments in idList.

\n

Parameters:

\n
    \n
  • idList - An table specifying IDs of modal environments
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "160", + "lineno": "205", "name": "deactivate", "notes": [], "notes_gfm": "", @@ -11212,7 +11212,7 @@ "doc_gfm": "

Deactivate all active modal environments.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "179", + "lineno": "224", "name": "deactivateAll", "notes": [], "notes_gfm": "", @@ -11235,7 +11235,7 @@ "doc_gfm": "

Create a new modal keybindings environment

\n

Parameters:

\n
    \n
  • id - A string specifying ID of new modal keybindings
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "46", + "lineno": "57", "name": "new", "notes": [], "notes_gfm": "", @@ -11258,7 +11258,7 @@ "doc_gfm": "

Toggle the cheatsheet display of current modal environments's keybindings.

\n

Parameters:

\n
    \n
  • iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.
  • \n
  • force - A optional boolean value to force show cheatsheet, defaults to nil (automatically).
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "57", + "lineno": "126", "name": "toggleCheatsheet", "notes": [], "notes_gfm": "", @@ -11289,7 +11289,7 @@ "doc_gfm": "

Activate all modal environment in idList.

\n

Parameters:

\n
    \n
  • idList - An table specifying IDs of modal environments
  • \n
  • trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to nil.
  • \n
  • showKeys - A optional boolean value to show all available keybindings, defaults to nil.
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "129", + "lineno": "174", "name": "activate", "notes": [], "notes_gfm": "", @@ -11314,7 +11314,7 @@ "doc_gfm": "

Deactivate modal environments in idList.

\n

Parameters:

\n
    \n
  • idList - An table specifying IDs of modal environments
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "160", + "lineno": "205", "name": "deactivate", "notes": [], "notes_gfm": "", @@ -11337,7 +11337,7 @@ "doc_gfm": "

Deactivate all active modal environments.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "179", + "lineno": "224", "name": "deactivateAll", "notes": [], "notes_gfm": "", @@ -11360,7 +11360,7 @@ "doc_gfm": "

Create a new modal keybindings environment

\n

Parameters:

\n
    \n
  • id - A string specifying ID of new modal keybindings
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "46", + "lineno": "57", "name": "new", "notes": [], "notes_gfm": "", @@ -11383,7 +11383,7 @@ "doc_gfm": "

Toggle the cheatsheet display of current modal environments's keybindings.

\n

Parameters:

\n
    \n
  • iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.
  • \n
  • force - A optional boolean value to force show cheatsheet, defaults to nil (automatically).
  • \n
\n", "examples": [], "file": "Source/ModalMgr.spoon/init.lua", - "lineno": "57", + "lineno": "126", "name": "toggleCheatsheet", "notes": [], "notes_gfm": "", From 93fd06801a47daf4d3c803a1c3020a2da46d4d68 Mon Sep 17 00:00:00 2001 From: JonathanDoughty Date: Wed, 7 Aug 2024 09:16:25 -0400 Subject: [PATCH 15/55] bump versioni; address changes Monterey brought on (#266) --- Source/TimeMachineProgress.spoon/init.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/TimeMachineProgress.spoon/init.lua b/Source/TimeMachineProgress.spoon/init.lua index a650ab6d..e8e02a62 100644 --- a/Source/TimeMachineProgress.spoon/init.lua +++ b/Source/TimeMachineProgress.spoon/init.lua @@ -13,7 +13,7 @@ obj.__index = obj -- Metadata obj.name = "TimeMachineProgress" -obj.version = "0.1" +obj.version = "0.2" obj.author = "Diego Zamboni " obj.homepage = "https://github.com/Hammerspoon/Spoons" obj.license = "MIT - https://opensource.org/licenses/MIT" @@ -132,7 +132,7 @@ function obj:refresh() -- Identify special states: preparing backup and stopping backup. local stopping = (data['Stopping'] == '1') - local preparing = (not stopping) and (data['Percent'] == '-1' or data['Percent'] == '0') + local preparing = (not stopping) and (data['Percent'] == '-1' or data['Percent'] == '0' or not data['Progress']) -- Depending on macOS version the 'Progress' data may be stored in a -- subitem, we promote it to the top level @@ -148,7 +148,11 @@ function obj:refresh() topmenu = tooltip elseif preparing then title = "(prep)" - tooltip = "Preparing Backup…" + if (data['BackupPhase']) then + tooltip = data['BackupPhase']:gsub("(%l)(%u)", "%1 %2") + else + tooltip = "Preparing Backup…" + end topmenu = tooltip else title = string.format("%.2f%%", tonumber(data['Percent'])*100) From 9c16738d2f3d71df7501dd04bfecd0ae6b217863 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:16:40 +0000 Subject: [PATCH 16/55] Generate docs for TimeMachineProgress --- Source/TimeMachineProgress.spoon/docs.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/TimeMachineProgress.spoon/docs.json b/Source/TimeMachineProgress.spoon/docs.json index cbaef2ac..b6ae931c 100644 --- a/Source/TimeMachineProgress.spoon/docs.json +++ b/Source/TimeMachineProgress.spoon/docs.json @@ -30,7 +30,7 @@ "doc": "Starts the indicator\n\nParameters:\n * None\n\nReturns:\n * The TimeMachineProgress object", "examples": [], "file": "Source/TimeMachineProgress.spoon//init.lua", - "lineno": "203", + "lineno": "207", "name": "start", "notes": [], "parameters": [ @@ -49,7 +49,7 @@ "doc": "Stops the indicator\n\nParameters:\n * None\n\nReturns:\n * The TimeMachineProgress object", "examples": [], "file": "Source/TimeMachineProgress.spoon//init.lua", - "lineno": "221", + "lineno": "225", "name": "stop", "notes": [], "parameters": [ @@ -163,7 +163,7 @@ "doc": "Starts the indicator\n\nParameters:\n * None\n\nReturns:\n * The TimeMachineProgress object", "examples": [], "file": "Source/TimeMachineProgress.spoon//init.lua", - "lineno": "203", + "lineno": "207", "name": "start", "notes": [], "parameters": [ @@ -182,7 +182,7 @@ "doc": "Stops the indicator\n\nParameters:\n * None\n\nReturns:\n * The TimeMachineProgress object", "examples": [], "file": "Source/TimeMachineProgress.spoon//init.lua", - "lineno": "221", + "lineno": "225", "name": "stop", "notes": [], "parameters": [ From 8f00423bf27b4cb496767e7c9ec225f01b034df6 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:16:40 +0000 Subject: [PATCH 17/55] Add binary package for TimeMachineProgress. --- Spoons/TimeMachineProgress.spoon.zip | Bin 4480 -> 4528 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Spoons/TimeMachineProgress.spoon.zip b/Spoons/TimeMachineProgress.spoon.zip index 779ccb552155c755b310302619228cfa5fced296..6cc8885c76bf2609baffe63b915f8071e0d4c41a 100644 GIT binary patch delta 4208 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 Date: Wed, 7 Aug 2024 13:16:41 +0000 Subject: [PATCH 18/55] Update docs --- docs/TimeMachineProgress.html | 4 ++-- docs/docs.json | 8 ++++---- docs/templated_docs.json | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/TimeMachineProgress.html b/docs/TimeMachineProgress.html index 6d7438ab..626e5399 100644 --- a/docs/TimeMachineProgress.html +++ b/docs/TimeMachineProgress.html @@ -183,7 +183,7 @@
start
Source - Source/TimeMachineProgress.spoon/init.lua line 203 + Source/TimeMachineProgress.spoon/init.lua line 207 @@ -220,7 +220,7 @@
stop
Source - Source/TimeMachineProgress.spoon/init.lua line 221 + Source/TimeMachineProgress.spoon/init.lua line 225 diff --git a/docs/docs.json b/docs/docs.json index 5bd5b07f..ce4ca5b0 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -16160,7 +16160,7 @@ "doc": "Starts the indicator\n\nParameters:\n * None\n\nReturns:\n * The TimeMachineProgress object", "examples": [], "file": "Source/TimeMachineProgress.spoon/init.lua", - "lineno": "203", + "lineno": "207", "name": "start", "notes": [], "parameters": [ @@ -16179,7 +16179,7 @@ "doc": "Stops the indicator\n\nParameters:\n * None\n\nReturns:\n * The TimeMachineProgress object", "examples": [], "file": "Source/TimeMachineProgress.spoon/init.lua", - "lineno": "221", + "lineno": "225", "name": "stop", "notes": [], "parameters": [ @@ -16293,7 +16293,7 @@ "doc": "Starts the indicator\n\nParameters:\n * None\n\nReturns:\n * The TimeMachineProgress object", "examples": [], "file": "Source/TimeMachineProgress.spoon/init.lua", - "lineno": "203", + "lineno": "207", "name": "start", "notes": [], "parameters": [ @@ -16312,7 +16312,7 @@ "doc": "Stops the indicator\n\nParameters:\n * None\n\nReturns:\n * The TimeMachineProgress object", "examples": [], "file": "Source/TimeMachineProgress.spoon/init.lua", - "lineno": "221", + "lineno": "225", "name": "stop", "notes": [], "parameters": [ diff --git a/docs/templated_docs.json b/docs/templated_docs.json index 5b04d20b..34206528 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -20371,7 +20371,7 @@ "doc_gfm": "

Starts the indicator

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The TimeMachineProgress object
  • \n
\n", "examples": [], "file": "Source/TimeMachineProgress.spoon/init.lua", - "lineno": "203", + "lineno": "207", "name": "start", "notes": [], "notes_gfm": "", @@ -20396,7 +20396,7 @@ "doc_gfm": "

Stops the indicator

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The TimeMachineProgress object
  • \n
\n", "examples": [], "file": "Source/TimeMachineProgress.spoon/init.lua", - "lineno": "221", + "lineno": "225", "name": "stop", "notes": [], "notes_gfm": "", @@ -20544,7 +20544,7 @@ "doc_gfm": "

Starts the indicator

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The TimeMachineProgress object
  • \n
\n", "examples": [], "file": "Source/TimeMachineProgress.spoon/init.lua", - "lineno": "203", + "lineno": "207", "name": "start", "notes": [], "notes_gfm": "", @@ -20569,7 +20569,7 @@ "doc_gfm": "

Stops the indicator

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The TimeMachineProgress object
  • \n
\n", "examples": [], "file": "Source/TimeMachineProgress.spoon/init.lua", - "lineno": "221", + "lineno": "225", "name": "stop", "notes": [], "notes_gfm": "", From acf460061aee72c2782865d26bf284399f4ff901 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 7 Aug 2024 15:17:21 +0200 Subject: [PATCH 19/55] Add AutoMuteOnSleep (#267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add AutoMuteOnWake * Convert tabs to spaces * Add trailing space * Misc improvements – Mute on `systemWillSleep` as well. This makes sure that sound doesn't play for a split second on wake. Also makes it more robust since we're muting all devices twice (if one of the two events doesn't trigger properly for example). – Set the volume to `0`, and only actually mute if setting the volume to 0 failed. It's more convenient to increase the volume starting from 0 in my experience than restoring the previous sound level. * Rename spoon to AutoMuteOnSleep * AutoMuteOnWake → AutoMuteOnSleep * Update init.lua --- Source/AutoMuteOnSleep.spoon/init.lua | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Source/AutoMuteOnSleep.spoon/init.lua diff --git a/Source/AutoMuteOnSleep.spoon/init.lua b/Source/AutoMuteOnSleep.spoon/init.lua new file mode 100644 index 00000000..b351a2c9 --- /dev/null +++ b/Source/AutoMuteOnSleep.spoon/init.lua @@ -0,0 +1,47 @@ +--- === AutoMuteOnSleep === +--- +--- Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep. +--- Useful to avoid blasting sound when opening a Macbook in the public transport. +--- Note: This is primarily intended for portable Mac devices, which have internal speakers. +--- +--- Download: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip) + + +local obj={} +obj.__index = obj + +-- Metadata +obj.name = "AutoMuteOnSleep" +obj.version = "1.0" +obj.author = "devnoname120 Date: Wed, 7 Aug 2024 13:17:37 +0000 Subject: [PATCH 20/55] Generate docs for AutoMuteOnSleep --- Source/AutoMuteOnSleep.spoon/docs.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Source/AutoMuteOnSleep.spoon/docs.json diff --git a/Source/AutoMuteOnSleep.spoon/docs.json b/Source/AutoMuteOnSleep.spoon/docs.json new file mode 100644 index 00000000..edaa4207 --- /dev/null +++ b/Source/AutoMuteOnSleep.spoon/docs.json @@ -0,0 +1,19 @@ +[ + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [], + "Variable": [], + "desc": "Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.", + "doc": "Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.\nUseful to avoid blasting sound when opening a Macbook in the public transport.\nNote: This is primarily intended for portable Mac devices, which have internal speakers.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip)", + "items": [], + "name": "AutoMuteOnSleep", + "stripped_doc": "Useful to avoid blasting sound when opening a Macbook in the public transport.\nNote: This is primarily intended for portable Mac devices, which have internal speakers.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip)", + "submodules": [], + "type": "Module" + } +] \ No newline at end of file From 2ff3153c2ddff1272689f443475792a3de6bf905 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:17:37 +0000 Subject: [PATCH 21/55] Add binary package for AutoMuteOnSleep. --- Spoons/AutoMuteOnSleep.spoon.zip | Bin 0 -> 1604 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Spoons/AutoMuteOnSleep.spoon.zip diff --git a/Spoons/AutoMuteOnSleep.spoon.zip b/Spoons/AutoMuteOnSleep.spoon.zip new file mode 100644 index 0000000000000000000000000000000000000000..20826a2fd762ec600b266a2d7e7be744673d14bc GIT binary patch literal 1604 zcmWIWW@h1H00HAH_DC=TN{BJYFgTW$Oi#IOmXkubu*v87hAcxbu%)HDJy`0iS zu(@xso4Yo|JO8qSz`oz%Jyn@XSIbTr9uit0_h7=e3r_qiy3D>=#O=Bl`Bpj8@x$$z zvDR&FOJ6mH%G|zx#{7NZyypR-qI>w~g&ll6bzfMAT2kb^=O4W`#Z^RdFO@sEkllX+ z!+pg!9<6eXQ3;X(AJi%Y7EWa0eV5Y9_hF&i$FFI??IlswfMRZDSJCdJs$@RQz z(a)QS(jhEI`%;*tRp(5v;_hq8W7CqnA}Dn6MB59wC4P=GHw12C%Wo}fTO;oiH|e%X6~S@-f-zFE|=5pE`FYqjJ>7>prb<9B@!t8oWIEoe>pBX>D_su-Ko z-g`VXHTe9Ft==n_%1@0;Dc^ZD1!t9Yb$tA5w4CFeh$*yG@R=*XrQ z&AxNqm?Kg)D5rRRTrJ(k$iQ%kg@HjHXUa~=PcGKWD$dWtmu21tZR`^<~jRpIu$w;Z+Dt^WOs6Gl6&Xo(~UpMjSln964mWs)9jq`e0uuv^X1_T_iwSi zh|BKL*mwKT-G5b$OC-Afwmp62^I2-&!YL;gUTi%ey{v#Ur0|$lc8=}j^vQ|nZd|mV4<&i$F3*zo4AB3(* zS!MQ*YmU3njfKsNw?$9ZY1GKwrMmlH^ONtNHeOiR#(8k^rgp^y!)eMQYai9`yX<1* zXraloivNI7_>@-yHyTr?OfreST)o^a`iDVL~c~9ZFJ}XCq^B_{iK{_TgVb z9+jRxn%5%eZ?buFLc=5ud5!7IYV^&krY(3eJAHAa*6n@vn|e!cSoHpl?%8NKdDWNg zmm`1mJh$8SKOkUI|>i?jY`VGkI3;t+NZ)HQrzU%^p~AF*3<9<0=XzpoO9U!&^rX z6Ia2=3Mm*d3Pq6FxQa!H*}$~Ku%s~nr`d=?5@-jgki=sLW&%aFLkn0|V|PDNa>eBl URyL6LnSoFh=weP_xz4}<00Nbc%>V!Z literal 0 HcmV?d00001 From e9ca923b8e532f3d61eff06b8fd4fc37cc0953f3 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:17:38 +0000 Subject: [PATCH 22/55] Update docs --- docs/AutoMuteOnSleep.html | 29 +++++++++++++++++++++++++++++ docs/docs.json | 17 +++++++++++++++++ docs/docs_index.json | 5 +++++ docs/index.html | 5 +++++ docs/templated_docs.json | 19 +++++++++++++++++++ 5 files changed, 75 insertions(+) create mode 100644 docs/AutoMuteOnSleep.html diff --git a/docs/AutoMuteOnSleep.html b/docs/AutoMuteOnSleep.html new file mode 100644 index 00000000..ef68fb2d --- /dev/null +++ b/docs/AutoMuteOnSleep.html @@ -0,0 +1,29 @@ + + + + Hammerspoon docs: AutoMuteOnSleep + + + + +
+

docs » AutoMuteOnSleep

+

Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep. +Useful to avoid blasting sound when opening a Macbook in the public transport. +Note: This is primarily intended for portable Mac devices, which have internal speakers.

+

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip

+ +
+

API Overview

+
    +
+

API Documentation

+ + \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index ce4ca5b0..5557a244 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -845,6 +845,23 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [], + "Variable": [], + "desc": "Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.", + "doc": "Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.\nUseful to avoid blasting sound when opening a Macbook in the public transport.\nNote: This is primarily intended for portable Mac devices, which have internal speakers.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip)", + "items": [], + "name": "AutoMuteOnSleep", + "stripped_doc": "Useful to avoid blasting sound when opening a Macbook in the public transport.\nNote: This is primarily intended for portable Mac devices, which have internal speakers.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], diff --git a/docs/docs_index.json b/docs/docs_index.json index 08451252..32921735 100644 --- a/docs/docs_index.json +++ b/docs/docs_index.json @@ -155,6 +155,11 @@ "name": "createTask", "type": "Method" }, + { + "desc": "Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.", + "name": "AutoMuteOnSleep", + "type": "Module" + }, { "desc": "Use Bing daily picture as your wallpaper, automatically.", "name": "BingDaily", diff --git a/docs/index.html b/docs/index.html index a552c5cb..c49a1792 100644 --- a/docs/index.html +++ b/docs/index.html @@ -97,6 +97,11 @@

API documentation

Asana

Simple spoon that creates a new task in Asana with a given name in a given workspace.

+ + + + AutoMuteOnSleep +

Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.

diff --git a/docs/templated_docs.json b/docs/templated_docs.json index 34206528..0e7c4259 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -1081,6 +1081,25 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [], + "Variable": [], + "desc": "Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.", + "desc_gfm": "

Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.

\n", + "doc": "Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.\nUseful to avoid blasting sound when opening a Macbook in the public transport.\nNote: This is primarily intended for portable Mac devices, which have internal speakers.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip)", + "doc_gfm": "

Automatically set to 0 the volume of all output audio devices except Bluetooth devices when Mac goes to sleep.\nUseful to avoid blasting sound when opening a Macbook in the public transport.\nNote: This is primarily intended for portable Mac devices, which have internal speakers.

\n

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip

\n", + "items": [], + "name": "AutoMuteOnSleep", + "stripped_doc": "Useful to avoid blasting sound when opening a Macbook in the public transport.\nNote: This is primarily intended for portable Mac devices, which have internal speakers.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/AutoMuteOnSleep.spoon.zip)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], From acd21d18343c69506d95d43f271a5695197a761e Mon Sep 17 00:00:00 2001 From: Raj Shah Date: Wed, 7 Aug 2024 06:17:52 -0700 Subject: [PATCH 23/55] Fix createArrangement dialog msg (#269) --- Source/ArrangeDesktop.spoon/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ArrangeDesktop.spoon/init.lua b/Source/ArrangeDesktop.spoon/init.lua index 09df850f..fef02702 100644 --- a/Source/ArrangeDesktop.spoon/init.lua +++ b/Source/ArrangeDesktop.spoon/init.lua @@ -202,7 +202,7 @@ function obj:createArrangement() return end - hs.dialog.blockAlert("We will now record each of your application windows.", "Each will window will flash into focus. The first focus on each monitor will prompt you to name the monitor.") + hs.dialog.blockAlert("We will now record each of your application windows.", "Each window will flash into focus. The first focus on each monitor will prompt you to name the monitor.") config[arrangementName] = obj:_buildArrangement(arrangementName) From e4a176237ab988e4e1e49507037d90ac458c9d1c Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:18:16 +0000 Subject: [PATCH 24/55] Add binary package for ArrangeDesktop. --- Spoons/ArrangeDesktop.spoon.zip | Bin 4112 -> 4110 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Spoons/ArrangeDesktop.spoon.zip b/Spoons/ArrangeDesktop.spoon.zip index be4d6495fd8b9a5829f1a30a959861675d305817..0c9b5cfd00cc8f03cc7071342e21de4ca43d40c7 100644 GIT binary patch delta 474 zcmbQB(5Ju`;LXg!#Q*{xS?rM$`Ls+VN;ao~aA^fM10%~zW(Ee9dZ08&p$G#L0|$c> zP+?4IDSND&{&>GW-dsI>aqB$pxPr)q zQLEDPjx)ULQ>bFD7P{zTuKMNTtzY%6mKvYc*TwA>Zn(Joe!`J>=WmHkkr8$Tb^ znH+3$?-MUeY;f>}v}{erLg!1o`44tfrBpsXqwiRy$eQKo;4 z1u6_!;hvDj!N6cB!@wZRAT#+OznEfXUS^42PHAFj2qy!x63_%SG*dP%KFeP3GG$-R z;^&K=r1`2EFWzRclxcqhOY&U?G4~_)F3OkmY7dCp)%ip z{*U!r|1%;y2?~wL5}d{&*n(qoJZCd23s}iBJ_{YJp~c7~$BZSsCVTOl+kpZHBX|)S zKn63{+FUGQWnh?T&A=eXAOVgcMj*MQk!SLLel<<3cCxa8)G-605>V|8J`fK8x=)>m From b842c242c9884326af4f1d41f19477500c588bb4 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:18:17 +0000 Subject: [PATCH 25/55] Update docs From 3bb667ecf331f7f6f6b84fe5c275b31c580a94b4 Mon Sep 17 00:00:00 2001 From: Yann Rouillard Date: Wed, 7 Aug 2024 15:18:56 +0200 Subject: [PATCH 26/55] fix seal plugins cmd being ignored in commands table (#271) Seal plugins can define a table of commands which contains the command used to launch it in the `cmd` field. However currently the key of the command in the commands table is used instead of this field. This was identical for most seal plugin except filesearch which uses the special ' character as the command trigger. --- Source/Seal.spoon/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Seal.spoon/init.lua b/Source/Seal.spoon/init.lua index c520d756..30813ba1 100644 --- a/Source/Seal.spoon/init.lua +++ b/Source/Seal.spoon/init.lua @@ -301,9 +301,9 @@ function obj.choicesCallback() end query_words = table.concat(query_words, " ") -- First get any direct command matches - for command,cmdInfo in pairs(obj.commands) do + for _,cmdInfo in pairs(obj.commands) do cmd_fn = cmdInfo["fn"] - if cmd:lower() == command:lower() then + if cmd:lower() == cmdInfo["cmd"]:lower() then if (query_words or "") == "" then query_words = ".*" end From 5e80b906f26561442c6dda83c6d95c35c093d038 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:19:20 +0000 Subject: [PATCH 27/55] Add binary package for Seal. --- Spoons/Seal.spoon.zip | Bin 55784 -> 55787 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Spoons/Seal.spoon.zip b/Spoons/Seal.spoon.zip index a730189ab82d5554da5c7cca6ea7e226b4160285..2cab1890e766c44c9c78703b8146dfc9cc3a6ddb 100644 GIT binary patch delta 3810 zcma)92{=@38$Qe+yRi(7Wyn_6zA+!ko-C0_hDgX~$w(zjN=%lJnG(lVwj@i+o@KnHWN#Ou*KK z#WGk%vI)zb_AGMR8eTrk01fm51OT8o>gO#WH$V&Q0i38nMM@1ml?4ElKt@g^w=orN z@khGruZQSQb&r=y1-=Jmd1osnVc(?u+s$>He*Dn9mT^F5i)M~%Twi7~AgWw9BG&uEb3Q4bU zaLJ8^x9rzVEFi)Ihm+esPMNM(+$C$rWkTIQ-rjuqKxmA~YZf)~um(fo|%eQVVQ zBrY1%vWcNA>`hb83W512Po_dY{F<-v#7nl0(EY?qDXQbjQLYy|T4NkvD zb|h`AN@_oHGfzK=^QtNbB$^u~g~w!yzD+^XHOAHAX(X!di(1!1MziiY6!By!3p`>%piQ$88~xZ>HGhqY^c=j|k98 z-(dFf+6fyt-J`^EQD>IL%iU><%grC8A_&aic$9=beJR25#OXM*<_*u}hqI*WN!|wz z@B|K!WykulucCxLIyA1CFPv&v+xxu;ez4)tc;X3AeKyhhq1roW-|Vq_63oE-Tni z(?KJ0Q@@ebf#~Q_Fpzr>%29y2o+)--w&7d7{n2F{wnS^6_v`YFRZZV>GWT$7l5&b7 z!G2*6a~TanI#Tg2W0j8&d=Ddf#>pkv0Uf}qW)z(0sg%MJj;8B#u%L8#n6)az$1JrxV&#^ zAyumGuCP}uaXpQJS3hRCvrDWnr)^+H?qdR~X*xT}`fipp;cdCk1oJ*eHx?SXH@{9{ zX;!{BGO*yzZy)R?A6wFv*5|GQQ`zuc7J5?nlxJWrg2`(o(A!gkJ?1E8&k?Tx4oxT_ zF8M3HixB;XX`zL(6-K*@lrENmDx8Viug?8?Wj) zKN?F6k>~u29@B?Jt?k!Yevs^6tf#dP3o^{9F$t-yxk)HHuajK#(~=5ZT*7M2&EB$utwvhn{rJF$eON1nGv@_zAKu3H*%M8Ph2r?+AnFhNnd3`8_$mIwLYls)2dsW zEc$1@UQeCLg0S%k7rY=8 zaf}Da8D(^(m2`Zy*u#a^Cw+Fj&#pZbv_}}RTTI+E8k@9Pi3(Y=SYLMrNeCgD32+#p zBjC}UaBN-r!&OA58dHX*y=z%PtOpi32${MnKL@Jw3(~lO*8JyaDnSyz55#|M4OA9* ziYuN@V~$^imrF8ej$CM(J2ItR7(iir8Ek${9vd9}dC%*^7!`#m;U%s=GCj=_PqQ3D zwU0zhMLi=?O6O1JQP_kzpjLyP7hdwqg>)TVu)QmY@}cp!K1@F0KRi)mSr79#uhyg{ zqbnUU^m1N1sG#xMC>CeLE32KPq3Y8=J&xmEB8e~+5YsVW+ z-E z2qNjOx5Ycz#iy$!Z)^(PS2dK?vb+{2z^TiP&r^L5*#Yxir1e^?XpoHpry7@@!Y z4fyh~?2fjkh)(4MEo{pIaRsg|F40qc6E^?|f$fL6z^YyjUPb`2lN%~h4y0v(ZiRt) z%rZMO&oi^q|6n!^W|}mk0{~{&f0)Dje$Tu{I7he5+}8M;nqf_Ze?!#r={{%)`T+Gi;M-~#xz>^DF|9ghQa z003m?giFwE_tF2D@Sl0W&29v(0xQVhgB0CryZ;A|>_tH8*#VFyP-M3m@LdQ97cT&k zm=U`TvF=0AItYS3ec~FsD2gSbl$o`OntA`Ogih#2Kmu9;kboAE`Q5Uhqi)0iz(KuPsZZq2 Ht+#&x`&I7< delta 3803 zcma)<2{@GP8h}4D_A!RY*o`LH_be^HEfTV)X^>3FzSd|m7^EbQX?)3VE6FcQ+GI$U zY?C$F4Jnm5Gba~Bf^Trck01N9B6aZL>%*UIcAOHb4f#*yRB;@WDl-q(Vd7jG$WBm(} zMk;NM;E-^3_$ERft}?yJ0|43-XQ?ew3RxWGH|Q?VU=_71$Umt;M7{5dBc;XN(Jzu% zQ=edblD4ExX_X@No0JSMnswyRXzXed}?>&5iv8A?5fR(%3u`kgHu+F=N=V z=cxY)wwLY&seZRC7V$Q4iwn(N&hpB?+a~I|omFOi_S>BaQhz{gcyMc9j?LG`wBhK8 zR)T|fD9uHe>s|3Rd7T~S9{m}e5-tmIZ%GimmKuUF%w6dde4W3)t-mFlK?Dx6BteNE zr?~?wu)b)^L!4NJBIhR~>4600z&`WgIYNY~ab=-#v&x+A3~gdhYWlkxeDOSxExn_* z9Cs;7n2rb`Wn7fA?GNvKZ{;i9avhUbz!of_>S` zpT09Kp<~?V1TXMBjkcgXDhqUZsK#cfcEq_)!M6DdHYjfcEl zJt6JU(dnL=YT`PYV4YDR^hdM--rk{*c7K8Mu*KPjB*oB!5%}g67WPs%2W4%@V!^8f z*%JCa8yf-p8N_Vn`pkrg<^vWu0u5f)og369<4%m1_`>;BW)8Rb ztk+G4CI%LzUshQbP5)A)fV)jPa(=b`7Ee4Cn^L#d$ui+1t599)B{jM$KxCHh_u0bK zjt2u=B$%(+sG}BM;dtSjn_;>U-1+WjQuphlR?V>l(Y7pI=W!o>(Mr1^f9V|Df^$}r z!5D8&(&0!Syw#s{n3TRXP4yjl!b_Z=oCPI=oqF-lMi zuIYl$XJMB0#CAzq>rpFP_&9?1iS&zyeFpV|q{Ts->)EM}tfn#&tAMF%xhW-+e`P2EGJ z>J>C%C9~WixyLwt&}C7cMLR9R@N$6gBOI~7E*YI`V>j9xeV!TZFlcC*%u3EK6<-ib;HQ&{=vlW8GPH9Sw0ZU_en3NVvn4Nd7MgKG$T205k1~@lG;!+F?QJYNPhXf(zmlp z_tI2_lKrY(mwQI2N=Cq|BTe=Z zG&ah!N_OKeb^Hva&C6@_s`b_P);VJ{`kxLadAXx~Gwx^YETv58S+DWaKW=PV?_Vy8z^*YL*2f>GI z|6n15dh8Amy&*7#{Q!$9*vY<=lw!M~u+Ua$FcLN8?Vd}$hd1%U^d5xl5`rMS{>rLW7V5)3cPgJceJNb5I53c*2@u0+ zwsS!s*)pVE&-!!eS#JoTVD{aBYv)(6l+zM{d>>^w^1+3XeECo0`Z^Ni=aOU@0oAxn z#4UO=%+?jB&Wm>c#+_$y+PD1Cjk7*dL(tK(js=jyCBfncKH$Q!WP$wL1ZddmG?>U; zL~^MuUs}>S8jc(W*-?So9_N*p_2|!IIO>e*E0J0dSgeqWbKR>WQ9V`-iCt#Fr&ISd z8=u$TVexpC`nJlnn0kO@z~g1v-6<7VE^H@IOVSIajf^pHQ>X*A_yi795z~9O@p6oZ z!o|WN0yT)a#_{opqBX7I5*~+divu31q_{&pnqe8Lr%i^wP`tbl`*tLpoD(P5sUT9D zp`RzPLcE4bjO!;asx$6n6`wqY8(h8= zH8WeBU-@~>(`i_TJj`LySw>!1GbQ<3yXY^xTpBFmS)H9}iEzL~x@8L!gU@u--tdD< zC69}>n;Z6rWEO^+=-PD-1*T+3NQAjwNc*y|`u@U!plE8{VpqB9?`v`4;o){i);-VZ z4i0CQH9UCVsz-c5d$%#VlHJ#sKu)fg>ArmbT@*{DJ>zuFS6Yy2b^5v(Q-@$bd}vdg z!1yQff?JtW3GIpP&hI`%Zr9vWa!UHzSJ-%dvMWQl^44e!+zRr;u9P*lMmFv0J2K^? zy)~lgYq;+_((_>7)`;{&ch(;W;umR)@j*DgBVsMT7|5e#50rP)^z34}KOAEN02n{` z1|bA?^ztFO0O*zi`BVbO_B|{?^H+|kDWmfpkwpKZQK!&}KayKeP}#afb;VH@UKWTX z^xysq4s@%ax0K&a?r-|L)GrD#0YLb`9{tTC{>znr#-s5UT>y3fh>-#SBq02kZnH4I zbE9v=K-XSL(l%oJ%as)XK;Wks%lrUf?}77EIU5uh7@+DM;C)WT507(T_WQ36|BvK0 zm+tO>RIq*k2^p3IUk`|FtNLiVC?s$%m_?T{*hc1NyV)!ZApju7oPXh;GN|ijQ~Ri6w%x01US+o3K@+C*Lq~Og^SWfq3ZDfsL--|yS3f!6@~th2!PQN(%UQy zE9bmVSO)-PnYYxB!ZufEZnSMOvq#%n;5;eT0wfLqI41U=Q(V^!O7}@^XOj>ZXuh}1 lT~Ww9af Date: Wed, 7 Aug 2024 13:19:21 +0000 Subject: [PATCH 28/55] Update docs From 209078964afee95448b5d6629f4ba3d04d0b39b9 Mon Sep 17 00:00:00 2001 From: Muescha <184316+muescha@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:20:03 +0200 Subject: [PATCH 29/55] EmmyLua: save timestamps of docs.json to skip if no change (#278) * save timestamps of docs.json * add timestampsChanged * Update Source/EmmyLua.spoon/init.lua Co-authored-by: Muescha <184316+muescha@users.noreply.github.com> * change formatting - remove whitespace change formatting - remove whitespace - to get CI Checks run again --------- Co-authored-by: Chris Jones --- Source/EmmyLua.spoon/init.lua | 52 +++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/Source/EmmyLua.spoon/init.lua b/Source/EmmyLua.spoon/init.lua index 284c17d6..4722cd1f 100644 --- a/Source/EmmyLua.spoon/init.lua +++ b/Source/EmmyLua.spoon/init.lua @@ -27,9 +27,14 @@ M.name = "EmmyLua" M.version = "1.0" M.author = "http://github.com/folke" M.license = "MIT - https://opensource.org/licenses/MIT" +M.logger = hs.logger.new("EmmyLua") + local options = { annotations = hs.spoons.resourcePath("annotations"), + timestampsFilename = hs.spoons.resourcePath("annotations").."/timestamps.json", + timestamps = {}, + timestampsChanged = false, types = { bool = "boolean", boolean = "boolean", @@ -185,28 +190,69 @@ function M.create(jsonDocs, prefix) module.name = prefix .. module.name local fname = options.annotations .. "/" .. module.name .. ".lua" local fmtime = hs.fs.attributes(fname, "modification") + if fmtime == nil or mtime > fmtime then - -- print("creating " .. fname) + M.logger.i("creating " .. fname) local fd = io.open(fname, "w+") io.output(fd) M.processModule(module) io.close(fd) + else + M.logger.i("skipping " .. fname) end end end +function M.createWhenChanged(jsonDocs, prefix) + local mtime = hs.fs.attributes(jsonDocs, "modification") + local timestamp = options.timestamps[jsonDocs] + + if(timestamp == nil or mtime ~= timestamp) then + M.logger.i("reading "..jsonDocs) + M.create(jsonDocs, prefix) + options.timestamps[jsonDocs] = mtime + options.timestampsChanged = true + else + M.logger.i("skipping "..jsonDocs) + end +end + +function M.readTimestamps() + timestamps = hs.json.read(options.timestampsFilename) + + if timestamps then + options.timestamps = timestamps + end + + M.logger.d(hs.inspect(options.timestamps)) +end + +function M.writeTimestamps() + M.logger.d(hs.inspect(options.timestamps)) + if options.timestampsChanged then + hs.json.write(options.timestamps, options.timestampsFilename, true, true) + end +end + function M:init() + hs.fs.mkdir(options.annotations) + + M.readTimestamps() + -- Load hammerspoon docs - M.create(hs.docstrings_json_file) + M.createWhenChanged(hs.docstrings_json_file) -- Load Spoons for _, spoon in ipairs(hs.spoons.list()) do local doc = hs.configdir .. "/Spoons/" .. spoon.name .. ".spoon/docs.json" if hs.fs.attributes(doc, "modification") then - M.create(doc, "spoon.") + M.createWhenChanged(doc, "spoon.") end end + + M.writeTimestamps() + end return M From d4b08cbbe9d31897e1df1f94751f20510fd3a9fc Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:20:22 +0000 Subject: [PATCH 30/55] Add binary package for EmmyLua. --- Spoons/EmmyLua.spoon.zip | Bin 3250 -> 3482 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Spoons/EmmyLua.spoon.zip b/Spoons/EmmyLua.spoon.zip index bba097a027d6c48e3a5f845de8cee34840f93e93..951620dde6f75cf6d380dd6d3533007e82dc8774 100644 GIT binary patch delta 2663 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 BUvK~b From 780dd1cd4ff987f5613b0fc7ed329fd36162f8f6 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:20:23 +0000 Subject: [PATCH 31/55] Update docs From 83948355f4670214b05beaea2d004ef04f5d2f25 Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Wed, 7 Aug 2024 15:20:29 +0200 Subject: [PATCH 32/55] Add MiddleClickDragScroll (#296) * Add MiddleClickDragScroll * Block mouse events while dragging --- Source/MiddleClickDragScroll.spoon/init.lua | 261 ++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 Source/MiddleClickDragScroll.spoon/init.lua diff --git a/Source/MiddleClickDragScroll.spoon/init.lua b/Source/MiddleClickDragScroll.spoon/init.lua new file mode 100644 index 00000000..f4ab54bd --- /dev/null +++ b/Source/MiddleClickDragScroll.spoon/init.lua @@ -0,0 +1,261 @@ +--- === MiddleClickDragScroll === +--- +--- Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows. +--- Especially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse. +--- +--- Note: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position +--- where the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window. +--- +--- == Usage == +--- +--- ```lua +--- local MiddleClickDragScroll = hs.loadSpoon("MiddleClickDragScroll"):start() +--- ``` +--- +--- You can temporarily stop the spoon by calling `MiddleClickDragScroll:stop()` and then restart it by calling `MiddleClickDragScroll:start()` again. +--- +--- == Configuration == +--- +--- ```lua +--- local MiddleClickDragScroll = hs.loadSpoon("MiddleClickDragScroll"):configure{ +--- excludedApps = {"Some App", "Other app"}, -- Don't activate scrolling in apps with these names +--- excludedWindows = {"^Some Window Title$"}, -- Don't activate scrolling in windows with these names (supports regex, for exact match, use "^title$") +--- excludedUrls = {"^https://geogebra.calculator$"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger) +--- indicatorSize = 25, -- Size of the scrolling indicator in pixels +--- indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below. +--- { +--- type = "circle", +--- fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 }, +--- strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 }, +--- }, +--- startDistance = 15, -- Minimal distance to drag the mouse before scrolling is triggered. +--- scrollMode = "pixel", -- Whether the scroll speed is in "line"s or "pixel"s. Scrolling by lines has smooting in some applications +--- -- and therefore works with reduced frequency but it offers much less precise control. +--- scrollFrequency = 0.01, -- How often to trigger scrolling (in seconds) +--- scrollAccelaration = 30, -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster. +--- scrollSpeedFn = -- How scrolling accelerates based on the mouse distance from the initial location. +--- -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument +--- -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting). +--- function(self, x) +--- return (x ^ 2) / (self.scrollAccelaration ^ 2) +--- end +--- }:start() +--- ``` +--- +--- Unspecified keys are unchanged. You can call `configure` multiple times to dynamically change it but changing `indicatorAttributes` and `indicatorSize` only works when `MiddleClickDragScroll` is stopped. +--- +--- Instead of `indicatorSize` and `indicatorAttributes`, you can also pass a custom canvas to `configure` or set it directly to have more control over the indicator style: +--- +--- ```lua +--- MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{ +--- type = "circle", +--- fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 }, +--- strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 }, +--- } +--- ``` +--- +--- For more details, see: https://www.hammerspoon.org/docs/hs.canvas.html +--- +--- Download: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip) + +local MiddleClickDragScroll = {} + +MiddleClickDragScroll.author = "Benedikt Werner <1benediktwerner@gmail.com>" +MiddleClickDragScroll.homepage = "https://github.com/benediktwerner/MiddleClickDragScroll.spoon" +MiddleClickDragScroll.license = "MIT" +MiddleClickDragScroll.name = "MiddleClickDragScroll" +MiddleClickDragScroll.version = "1.0.0" +MiddleClickDragScroll.spoon = hs.spoons.scriptPath() + +MiddleClickDragScroll.excludedApps = {} -- Don't activate scrolling in apps with these names +MiddleClickDragScroll.excludedWindows = {} -- Don't activate scrolling in windows with these names (supports regex) +MiddleClickDragScroll.excludedUrls = {} -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger) +MiddleClickDragScroll.indicatorSize = 25 -- Size of the scrolling indicator in pixels +MiddleClickDragScroll.indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas. +{ + type = "circle", + fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 }, + strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 }, +} +MiddleClickDragScroll.startDistance = 15 -- Minimal distance to drag the mouse before scrolling is triggered. +MiddleClickDragScroll.scrollMode = "pixel" -- Whether the scroll speed is in "line"s or "pixel"s. Scrolling by lines has smooting in some applications and therefore works with reduced frequency but it offers much less precise control. +MiddleClickDragScroll.scrollFrequency = 0.01 -- How often to trigger scrolling (in seconds) +MiddleClickDragScroll.scrollAccelaration = 30 -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster. +MiddleClickDragScroll.scrollSpeedFn = -- How scrolling accelerates based on the mouse distance from the initial location. The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting) +function(self, x) + return (x ^ 2) / (self.scrollAccelaration ^ 2) +end + +local function signum(n) + if n > 0 then return 1 + elseif n < 0 then return -1 + else return 0 end +end + +local function getWindowUnderMouse() + -- Adapted from SkyRocket.spoon + -- Invoke `hs.application` because `hs.window.orderedWindows()` doesn't do it and breaks itself + local _ = hs.application + + local mousePos = hs.geometry.new(hs.mouse.absolutePosition()) + local screen = hs.mouse.getCurrentScreen() + + return hs.fnutils.find(hs.window.orderedWindows(), function(w) + return screen == w:screen() and mousePos:inside(w:frame()) + end) +end + +function MiddleClickDragScroll:init() + self.position = nil + self.isScrolling = false + self.timer = nil + + self.middleMouseDownEventTap = hs.eventtap.new({hs.eventtap.event.types.otherMouseDown}, self:handleMouseDown()) + self.middleMouseDraggedEventTap = hs.eventtap.new({hs.eventtap.event.types.otherMouseDragged}, self:handleMouseDragged()) + self.middleMouseUpEventTap = hs.eventtap.new({hs.eventtap.event.types.otherMouseUp}, self:handleMouseUp()) +end + +function MiddleClickDragScroll:handleMouseDown() + return function(event) + self.isScrolling = false + if self.timer ~= nil then + self.timer:stop() + self.timer = nil + end + + if event:getProperty(hs.eventtap.event.properties.mouseEventButtonNumber) ~= 2 then + return + end + + local window = getWindowUnderMouse() + if window == nil then return end + + local appTitle = window:application():title() + if hs.fnutils.some(self.excludedApps, function(a) return a == appTitle end) then return end + + local windowTitle = window:title() + if hs.fnutils.some(self.excludedWindows, function(w) return windowTitle:match(w) end) then return end + + if appTitle == "Safari" and #self.excludedUrls > 0 then + local _, url = hs.osascript.applescript('tell application "Safari" to return URL of current tab of front window') + if hs.fnutils.some(self.excludedUrls, function(u) return url:match(u) end) then return end + end + + if appTitle == "Google Chrome" and #self.excludedUrls > 0 then + local _, url = hs.osascript.applescript('tell application "Google Chrome" to return URL of active tab of front window') + if hs.fnutils.some(self.excludedUrls, function(u) return url:match(u) end) then return end + end + + self.startPos = event:location() + + return true + end +end + +function MiddleClickDragScroll:handleMouseDragged() + return function(event) + if event:getProperty(hs.eventtap.event.properties.mouseEventButtonNumber) ~= 2 or self.startPos == nil then + return + end + + local loc = event:location() + if loc == nil then + return true + end + + self.currPos = loc + + if self.isScrolling then + return true + end + + if (loc.x - self.startPos.x) ^ 2 + (loc.y - self.startPos.y) ^ 2 > self.startDistance ^ 2 then + self.isScrolling = true + local frame = self.canvas:frame() + self.canvas:topLeft{ x = self.startPos.x - frame.w / 2, y = self.startPos.y - frame.h / 2 }:show() + self.timer = hs.timer.doEvery(self.scrollFrequency, function(t) + local xDiff = self.startPos.x - self.currPos.x + local yDiff = self.startPos.y - self.currPos.y + hs.eventtap.scrollWheel( + { + math.floor(self:scrollSpeedFn(xDiff)) * signum(xDiff), + math.floor(self:scrollSpeedFn(yDiff)) * signum(yDiff), + }, + {}, + self.scrollMode + ) + end) + end + + return true + end +end + +function MiddleClickDragScroll:handleMouseUp() + return function(event) + if event:getProperty(hs.eventtap.event.properties.mouseEventButtonNumber) ~= 2 or self.startPos == nil then + return + end + + if self.timer ~= nil then + self.timer:stop() + self.timer = nil + end + + self.startPos = nil + self.canvas:hide() + + if not self.isScrolling then + self.middleMouseDownEventTap:stop() + self.middleMouseUpEventTap:stop() + hs.eventtap.middleClick(event:location(), 1) + self.middleMouseUpEventTap:start() + self.middleMouseDownEventTap:start() + end + + return true + end +end + +function MiddleClickDragScroll:configure(options) + self.excludedApps = options.excludedApps or self.excludedApps + self.excludedWindows = options.excludedWindows or self.excludedWindows + self.excludedUrls = options.excludedUrls or self.excludedUrls + self.startDistance = options.startDistance or self.startDistance + self.scrollMode = options.scrollMode or self.scrollMode + self.scrollFrequency = options.scrollFrequency or self.scrollFrequency + self.scrollSpeed = options.scrollSpeed or self.scrollSpeed + self.scrollSpeedFn = options.scrollSpeedFn or self.scrollSpeedFn + self.canvas = options.canvas or self.canvas + self.indicatorSize = options.indicatorSize or self.indicatorSize + self.indicatorAttributes = options.indicatorAttributes or self.indicatorAttributes + if options.indicatorSize or options.indicatorAttributes then + self.canvas = nil + end + return self +end + +function MiddleClickDragScroll:start() + if self.canvas == nil then + self.canvas = hs.canvas.new{ w = self.indicatorSize, h = self.indicatorSize } + self.canvas:insertElement(self.indicatorAttributes) + end + + self.middleMouseDownEventTap:start() + self.middleMouseDraggedEventTap:start() + self.middleMouseUpEventTap:start() + return self +end + +function MiddleClickDragScroll:stop() + self.middleMouseDownEventTap:stop() + self.middleMouseDraggedEventTap:stop() + self.middleMouseUpEventTap:stop() + return self +end + +function MiddleClickDragScroll:isEnabled() + return self.middleMouseDownEventTap:isEnabled() +end + +return MiddleClickDragScroll From 2be0bb5c5ad309ba2da10d8aac27e209907f1b46 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:20:46 +0000 Subject: [PATCH 33/55] Generate docs for MiddleClickDragScroll --- Source/MiddleClickDragScroll.spoon/docs.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Source/MiddleClickDragScroll.spoon/docs.json diff --git a/Source/MiddleClickDragScroll.spoon/docs.json b/Source/MiddleClickDragScroll.spoon/docs.json new file mode 100644 index 00000000..564af49a --- /dev/null +++ b/Source/MiddleClickDragScroll.spoon/docs.json @@ -0,0 +1,19 @@ +[ + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [], + "Variable": [], + "desc": "Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.", + "doc": "Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.\nEspecially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse.\n\nNote: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position\nwhere the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window.\n\n== Usage ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):start()\n```\n\nYou can temporarily stop the spoon by calling `MiddleClickDragScroll:stop()` and then restart it by calling `MiddleClickDragScroll:start()` again.\n\n== Configuration ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):configure{\n excludedApps = {\"Some App\", \"Other app\"}, -- Don't activate scrolling in apps with these names\n excludedWindows = {\"^Some Window Title$\"}, -- Don't activate scrolling in windows with these names (supports regex, for exact match, use \"^title$\")\n excludedUrls = {\"^https://geogebra.calculator$\"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger)\n indicatorSize = 25, -- Size of the scrolling indicator in pixels\n indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below.\n {\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n },\n startDistance = 15, -- Minimal distance to drag the mouse before scrolling is triggered.\n scrollMode = \"pixel\", -- Whether the scroll speed is in \"line\"s or \"pixel\"s. Scrolling by lines has smooting in some applications\n -- and therefore works with reduced frequency but it offers much less precise control.\n scrollFrequency = 0.01, -- How often to trigger scrolling (in seconds)\n scrollAccelaration = 30, -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster.\n scrollSpeedFn = -- How scrolling accelerates based on the mouse distance from the initial location.\n -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument\n -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting).\n function(self, x)\n return (x ^ 2) / (self.scrollAccelaration ^ 2)\n end\n}:start()\n```\n\nUnspecified keys are unchanged. You can call `configure` multiple times to dynamically change it but changing `indicatorAttributes` and `indicatorSize` only works when `MiddleClickDragScroll` is stopped.\n\nInstead of `indicatorSize` and `indicatorAttributes`, you can also pass a custom canvas to `configure` or set it directly to have more control over the indicator style:\n\n```lua\n MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n }\n```\n\nFor more details, see: https://www.hammerspoon.org/docs/hs.canvas.html\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip)", + "items": [], + "name": "MiddleClickDragScroll", + "stripped_doc": "Especially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse.\n\nNote: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position\nwhere the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window.\n\n== Usage ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):start()\n```\n\nYou can temporarily stop the spoon by calling `MiddleClickDragScroll:stop()` and then restart it by calling `MiddleClickDragScroll:start()` again.\n\n== Configuration ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):configure{\n excludedApps = {\"Some App\", \"Other app\"}, -- Don't activate scrolling in apps with these names\n excludedWindows = {\"^Some Window Title$\"}, -- Don't activate scrolling in windows with these names (supports regex, for exact match, use \"^title$\")\n excludedUrls = {\"^https://geogebra.calculator$\"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger)\n indicatorSize = 25, -- Size of the scrolling indicator in pixels\n indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below.\n {\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n },\n startDistance = 15, -- Minimal distance to drag the mouse before scrolling is triggered.\n scrollMode = \"pixel\", -- Whether the scroll speed is in \"line\"s or \"pixel\"s. Scrolling by lines has smooting in some applications\n -- and therefore works with reduced frequency but it offers much less precise control.\n scrollFrequency = 0.01, -- How often to trigger scrolling (in seconds)\n scrollAccelaration = 30, -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster.\n scrollSpeedFn = -- How scrolling accelerates based on the mouse distance from the initial location.\n -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument\n -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting).\n function(self, x)\n return (x ^ 2) / (self.scrollAccelaration ^ 2)\n end\n}:start()\n```\n\nUnspecified keys are unchanged. You can call `configure` multiple times to dynamically change it but changing `indicatorAttributes` and `indicatorSize` only works when `MiddleClickDragScroll` is stopped.\n\nInstead of `indicatorSize` and `indicatorAttributes`, you can also pass a custom canvas to `configure` or set it directly to have more control over the indicator style:\n\n```lua\n MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n }\n```\n\nFor more details, see: https://www.hammerspoon.org/docs/hs.canvas.html\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip)", + "submodules": [], + "type": "Module" + } +] \ No newline at end of file From d4f156641b8ac01c48d0f707386c809cc70ed97d Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:20:46 +0000 Subject: [PATCH 34/55] Add binary package for MiddleClickDragScroll. --- Spoons/MiddleClickDragScroll.spoon.zip | Bin 0 -> 5215 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Spoons/MiddleClickDragScroll.spoon.zip diff --git a/Spoons/MiddleClickDragScroll.spoon.zip b/Spoons/MiddleClickDragScroll.spoon.zip new file mode 100644 index 0000000000000000000000000000000000000000..b5b9f96b6b319542c7d421c52fe6e4a6555f3498 GIT binary patch literal 5215 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 Date: Wed, 7 Aug 2024 13:20:47 +0000 Subject: [PATCH 35/55] Update docs --- docs/MiddleClickDragScroll.html | 68 +++++++++++++++++++++++++++++++++ docs/docs.json | 17 +++++++++ docs/docs_index.json | 5 +++ docs/index.html | 5 +++ docs/templated_docs.json | 19 +++++++++ 5 files changed, 114 insertions(+) create mode 100644 docs/MiddleClickDragScroll.html diff --git a/docs/MiddleClickDragScroll.html b/docs/MiddleClickDragScroll.html new file mode 100644 index 00000000..2aad9ebb --- /dev/null +++ b/docs/MiddleClickDragScroll.html @@ -0,0 +1,68 @@ + + + + Hammerspoon docs: MiddleClickDragScroll + + + + +
+

docs » MiddleClickDragScroll

+

Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows. +Especially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse.

+

Note: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position +where the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window.

+

== Usage ==

+
local MiddleClickDragScroll = hs.loadSpoon("MiddleClickDragScroll"):start()
+
+

You can temporarily stop the spoon by calling MiddleClickDragScroll:stop() and then restart it by calling MiddleClickDragScroll:start() again.

+

== Configuration ==

+
local MiddleClickDragScroll = hs.loadSpoon("MiddleClickDragScroll"):configure{
+  excludedApps = {"Some App", "Other app"},         -- Don't activate scrolling in apps with these names
+  excludedWindows = {"^Some Window Title$"},        -- Don't activate scrolling in windows with these names (supports regex, for exact match, use "^title$")
+  excludedUrls = {"^https://geogebra.calculator$"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger)
+  indicatorSize = 25,   -- Size of the scrolling indicator in pixels
+  indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below.
+  {
+    type = "circle",
+    fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },
+    strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },
+  },
+  startDistance = 15,       -- Minimal distance to drag the mouse before scrolling is triggered.
+  scrollMode = "pixel",     -- Whether the scroll speed is in "line"s or "pixel"s. Scrolling by lines has smooting in some applications
+                            -- and therefore works with reduced frequency but it offers much less precise control.
+  scrollFrequency = 0.01,   -- How often to trigger scrolling (in seconds)
+  scrollAccelaration = 30,  -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster.
+  scrollSpeedFn =           -- How scrolling accelerates based on the mouse distance from the initial location.
+                            -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument
+                            -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting).
+  function(self, x)
+    return (x ^ 2) / (self.scrollAccelaration ^ 2)
+  end
+}:start()
+
+

Unspecified keys are unchanged. You can call configure multiple times to dynamically change it but changing indicatorAttributes and indicatorSize only works when MiddleClickDragScroll is stopped.

+

Instead of indicatorSize and indicatorAttributes, you can also pass a custom canvas to configure or set it directly to have more control over the indicator style:

+
MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{
+    type = "circle",
+    fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },
+    strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },
+  }
+
+

For more details, see: https://www.hammerspoon.org/docs/hs.canvas.html

+

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip

+ +
+

API Overview

+
    +
+

API Documentation

+ + \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index 5557a244..2c2ad770 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -8602,6 +8602,23 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [], + "Variable": [], + "desc": "Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.", + "doc": "Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.\nEspecially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse.\n\nNote: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position\nwhere the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window.\n\n== Usage ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):start()\n```\n\nYou can temporarily stop the spoon by calling `MiddleClickDragScroll:stop()` and then restart it by calling `MiddleClickDragScroll:start()` again.\n\n== Configuration ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):configure{\n excludedApps = {\"Some App\", \"Other app\"}, -- Don't activate scrolling in apps with these names\n excludedWindows = {\"^Some Window Title$\"}, -- Don't activate scrolling in windows with these names (supports regex, for exact match, use \"^title$\")\n excludedUrls = {\"^https://geogebra.calculator$\"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger)\n indicatorSize = 25, -- Size of the scrolling indicator in pixels\n indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below.\n {\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n },\n startDistance = 15, -- Minimal distance to drag the mouse before scrolling is triggered.\n scrollMode = \"pixel\", -- Whether the scroll speed is in \"line\"s or \"pixel\"s. Scrolling by lines has smooting in some applications\n -- and therefore works with reduced frequency but it offers much less precise control.\n scrollFrequency = 0.01, -- How often to trigger scrolling (in seconds)\n scrollAccelaration = 30, -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster.\n scrollSpeedFn = -- How scrolling accelerates based on the mouse distance from the initial location.\n -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument\n -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting).\n function(self, x)\n return (x ^ 2) / (self.scrollAccelaration ^ 2)\n end\n}:start()\n```\n\nUnspecified keys are unchanged. You can call `configure` multiple times to dynamically change it but changing `indicatorAttributes` and `indicatorSize` only works when `MiddleClickDragScroll` is stopped.\n\nInstead of `indicatorSize` and `indicatorAttributes`, you can also pass a custom canvas to `configure` or set it directly to have more control over the indicator style:\n\n```lua\n MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n }\n```\n\nFor more details, see: https://www.hammerspoon.org/docs/hs.canvas.html\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip)", + "items": [], + "name": "MiddleClickDragScroll", + "stripped_doc": "Especially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse.\n\nNote: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position\nwhere the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window.\n\n== Usage ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):start()\n```\n\nYou can temporarily stop the spoon by calling `MiddleClickDragScroll:stop()` and then restart it by calling `MiddleClickDragScroll:start()` again.\n\n== Configuration ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):configure{\n excludedApps = {\"Some App\", \"Other app\"}, -- Don't activate scrolling in apps with these names\n excludedWindows = {\"^Some Window Title$\"}, -- Don't activate scrolling in windows with these names (supports regex, for exact match, use \"^title$\")\n excludedUrls = {\"^https://geogebra.calculator$\"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger)\n indicatorSize = 25, -- Size of the scrolling indicator in pixels\n indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below.\n {\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n },\n startDistance = 15, -- Minimal distance to drag the mouse before scrolling is triggered.\n scrollMode = \"pixel\", -- Whether the scroll speed is in \"line\"s or \"pixel\"s. Scrolling by lines has smooting in some applications\n -- and therefore works with reduced frequency but it offers much less precise control.\n scrollFrequency = 0.01, -- How often to trigger scrolling (in seconds)\n scrollAccelaration = 30, -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster.\n scrollSpeedFn = -- How scrolling accelerates based on the mouse distance from the initial location.\n -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument\n -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting).\n function(self, x)\n return (x ^ 2) / (self.scrollAccelaration ^ 2)\n end\n}:start()\n```\n\nUnspecified keys are unchanged. You can call `configure` multiple times to dynamically change it but changing `indicatorAttributes` and `indicatorSize` only works when `MiddleClickDragScroll` is stopped.\n\nInstead of `indicatorSize` and `indicatorAttributes`, you can also pass a custom canvas to `configure` or set it directly to have more control over the indicator style:\n\n```lua\n MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n }\n```\n\nFor more details, see: https://www.hammerspoon.org/docs/hs.canvas.html\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], diff --git a/docs/docs_index.json b/docs/docs_index.json index 32921735..c84269cf 100644 --- a/docs/docs_index.json +++ b/docs/docs_index.json @@ -1618,6 +1618,11 @@ "name": "toggleMicMute", "type": "Method" }, + { + "desc": "Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.", + "name": "MiddleClickDragScroll", + "type": "Module" + }, { "desc": "With this script you will be able to move the window in halves and in corners using your keyboard and mainly using arrows. You would also be able to resize them by thirds, quarters, or halves.", "name": "MiroWindowsManager", diff --git a/docs/index.html b/docs/index.html index c49a1792..a9f4c1a9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -282,6 +282,11 @@

API documentation

MicMute

Microphone Mute Toggle and status indicator

+ + + + MiddleClickDragScroll +

Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.

diff --git a/docs/templated_docs.json b/docs/templated_docs.json index 0e7c4259..d9a7e22b 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -10970,6 +10970,25 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [], + "Variable": [], + "desc": "Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.", + "desc_gfm": "

Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.

\n", + "doc": "Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.\nEspecially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse.\n\nNote: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position\nwhere the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window.\n\n== Usage ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):start()\n```\n\nYou can temporarily stop the spoon by calling `MiddleClickDragScroll:stop()` and then restart it by calling `MiddleClickDragScroll:start()` again.\n\n== Configuration ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):configure{\n excludedApps = {\"Some App\", \"Other app\"}, -- Don't activate scrolling in apps with these names\n excludedWindows = {\"^Some Window Title$\"}, -- Don't activate scrolling in windows with these names (supports regex, for exact match, use \"^title$\")\n excludedUrls = {\"^https://geogebra.calculator$\"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger)\n indicatorSize = 25, -- Size of the scrolling indicator in pixels\n indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below.\n {\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n },\n startDistance = 15, -- Minimal distance to drag the mouse before scrolling is triggered.\n scrollMode = \"pixel\", -- Whether the scroll speed is in \"line\"s or \"pixel\"s. Scrolling by lines has smooting in some applications\n -- and therefore works with reduced frequency but it offers much less precise control.\n scrollFrequency = 0.01, -- How often to trigger scrolling (in seconds)\n scrollAccelaration = 30, -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster.\n scrollSpeedFn = -- How scrolling accelerates based on the mouse distance from the initial location.\n -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument\n -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting).\n function(self, x)\n return (x ^ 2) / (self.scrollAccelaration ^ 2)\n end\n}:start()\n```\n\nUnspecified keys are unchanged. You can call `configure` multiple times to dynamically change it but changing `indicatorAttributes` and `indicatorSize` only works when `MiddleClickDragScroll` is stopped.\n\nInstead of `indicatorSize` and `indicatorAttributes`, you can also pass a custom canvas to `configure` or set it directly to have more control over the indicator style:\n\n```lua\n MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n }\n```\n\nFor more details, see: https://www.hammerspoon.org/docs/hs.canvas.html\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip)", + "doc_gfm": "

Allows scrolling by holding down the middle mouse button and dragging it, the same as it works on Windows.\nEspecially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse.

\n

Note: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position\nwhere the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window.

\n

== Usage ==

\n
local MiddleClickDragScroll = hs.loadSpoon("MiddleClickDragScroll"):start()\n
\n

You can temporarily stop the spoon by calling MiddleClickDragScroll:stop() and then restart it by calling MiddleClickDragScroll:start() again.

\n

== Configuration ==

\n
local MiddleClickDragScroll = hs.loadSpoon("MiddleClickDragScroll"):configure{\n  excludedApps = {"Some App", "Other app"},         -- Don't activate scrolling in apps with these names\n  excludedWindows = {"^Some Window Title$"},        -- Don't activate scrolling in windows with these names (supports regex, for exact match, use "^title$")\n  excludedUrls = {"^https://geogebra.calculator$"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger)\n  indicatorSize = 25,   -- Size of the scrolling indicator in pixels\n  indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below.\n  {\n    type = "circle",\n    fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n    strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n  },\n  startDistance = 15,       -- Minimal distance to drag the mouse before scrolling is triggered.\n  scrollMode = "pixel",     -- Whether the scroll speed is in "line"s or "pixel"s. Scrolling by lines has smooting in some applications\n                            -- and therefore works with reduced frequency but it offers much less precise control.\n  scrollFrequency = 0.01,   -- How often to trigger scrolling (in seconds)\n  scrollAccelaration = 30,  -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster.\n  scrollSpeedFn =           -- How scrolling accelerates based on the mouse distance from the initial location.\n                            -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument\n                            -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting).\n  function(self, x)\n    return (x ^ 2) / (self.scrollAccelaration ^ 2)\n  end\n}:start()\n
\n

Unspecified keys are unchanged. You can call configure multiple times to dynamically change it but changing indicatorAttributes and indicatorSize only works when MiddleClickDragScroll is stopped.

\n

Instead of indicatorSize and indicatorAttributes, you can also pass a custom canvas to configure or set it directly to have more control over the indicator style:

\n
MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{\n    type = "circle",\n    fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n    strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n  }\n
\n

For more details, see: https://www.hammerspoon.org/docs/hs.canvas.html

\n

Download: https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip

\n", + "items": [], + "name": "MiddleClickDragScroll", + "stripped_doc": "Especially useful to quickly scroll to the top or bottom of a page, if you don't have a Magic Mouse.\n\nNote: Due to OS limitations, it always scrolls the window currently below the mouse, not the window below the position\nwhere the dragging started, like it works on Windows. You therefore need to take some care to stay inside the window.\n\n== Usage ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):start()\n```\n\nYou can temporarily stop the spoon by calling `MiddleClickDragScroll:stop()` and then restart it by calling `MiddleClickDragScroll:start()` again.\n\n== Configuration ==\n\n```lua\nlocal MiddleClickDragScroll = hs.loadSpoon(\"MiddleClickDragScroll\"):configure{\n excludedApps = {\"Some App\", \"Other app\"}, -- Don't activate scrolling in apps with these names\n excludedWindows = {\"^Some Window Title$\"}, -- Don't activate scrolling in windows with these names (supports regex, for exact match, use \"^title$\")\n excludedUrls = {\"^https://geogebra.calculator$\"}, -- Don't activate scrolling when the active window is on these URLs (supports regex, only works in Chrome and Safari, asks for extra permissions on first trigger)\n indicatorSize = 25, -- Size of the scrolling indicator in pixels\n indicatorAttributes = -- Attributes of the scrolling indicator. Takes any specified on https://www.hammerspoon.org/docs/hs.canvas.html#attributes. Alternatively, you can pass a custom canvas, see the explenation below.\n {\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n },\n startDistance = 15, -- Minimal distance to drag the mouse before scrolling is triggered.\n scrollMode = \"pixel\", -- Whether the scroll speed is in \"line\"s or \"pixel\"s. Scrolling by lines has smooting in some applications\n -- and therefore works with reduced frequency but it offers much less precise control.\n scrollFrequency = 0.01, -- How often to trigger scrolling (in seconds)\n scrollAccelaration = 30, -- How fast scrolling accelerates based on the mouse distance from the initial location. Larger is faster.\n scrollSpeedFn = -- How scrolling accelerates based on the mouse distance from the initial location.\n -- The default is dist^2 / scrollAcceleration^2. You can pass a custom function that recieves `self` as the first argument\n -- and the absolute distance as the second and returns the resulting speed (in pixels or lines, depending on the scrollMode setting).\n function(self, x)\n return (x ^ 2) / (self.scrollAccelaration ^ 2)\n end\n}:start()\n```\n\nUnspecified keys are unchanged. You can call `configure` multiple times to dynamically change it but changing `indicatorAttributes` and `indicatorSize` only works when `MiddleClickDragScroll` is stopped.\n\nInstead of `indicatorSize` and `indicatorAttributes`, you can also pass a custom canvas to `configure` or set it directly to have more control over the indicator style:\n\n```lua\n MiddleClickDragScroll.canvas = hs.canvas.new{ w = 25, h = 25}:insertElement{\n type = \"circle\",\n fillColor = { red = 0, green = 0, blue = 0, alpha = 0.3 },\n strokeColor = { red = 1, green = 1, blue = 1, alpha = 0.5 },\n }\n```\n\nFor more details, see: https://www.hammerspoon.org/docs/hs.canvas.html\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MiddleClickDragScroll.spoon.zip)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], From ea1f07ae4fcca08a6e7f8c9c744289008c49cd73 Mon Sep 17 00:00:00 2001 From: Jonathan Hitchcock Date: Wed, 7 Aug 2024 06:20:58 -0700 Subject: [PATCH 36/55] Make AClock recalculate canvas on screen change (#297) --- Source/AClock.spoon/init.lua | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/Source/AClock.spoon/init.lua b/Source/AClock.spoon/init.lua index 8d094c83..e046d880 100644 --- a/Source/AClock.spoon/init.lua +++ b/Source/AClock.spoon/init.lua @@ -60,6 +60,17 @@ for k, v in pairs(obj._attribs) do obj[k] = v end --- --- Returns: --- * The AClock object +function getframe(width, height) + local mainScreen = hs.screen.primaryScreen() + local mainRes = mainScreen:fullFrame() + return { + x = (mainRes.w - width) / 2, + y = (mainRes.h - height) / 2, + w = width, + h = height + } +end + function obj:init() if not self.canvas then self.canvas = hs.canvas.new({x=0, y=0, w=0, h=0}) end self.canvas[1] = { @@ -72,16 +83,19 @@ function obj:init() } local mainScreen = hs.screen.primaryScreen() local mainRes = mainScreen:fullFrame() - self.canvas:frame({ - x = (mainRes.w-self.width)/2, - y = (mainRes.h-self.height)/2, - w = self.width, - h = self.height, - }) + self.canvas:frame(getframe(self.width, self.height)) + self._screen_watcher = hs.screen.watcher.new(function() + self:update_canvas() + end) + self._screen_watcher:start() self._init_done = true return self end +function obj:update_canvas() + self.canvas:frame(getframe(self.width, self.height)) +end + function obj:update_clock_text() self.canvas[1].text = os.date(self.format) end From 5762a7c591b9e389e15cfa649510bf356d3958f5 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:21:14 +0000 Subject: [PATCH 37/55] Generate docs for AClock --- Source/AClock.spoon/docs.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/AClock.spoon/docs.json b/Source/AClock.spoon/docs.json index 4119951a..2047649f 100644 --- a/Source/AClock.spoon/docs.json +++ b/Source/AClock.spoon/docs.json @@ -13,7 +13,7 @@ "doc": "Hide AClock.\n\nParameters:\n * None\n\nReturns:\n * The AClock object", "examples": [], "file": "Source/AClock.spoon//init.lua", - "lineno": "116", + "lineno": "130", "name": "hide", "notes": [], "parameters": [ @@ -51,7 +51,7 @@ "doc": "Show AClock.\n\nParameters:\n * None\n\nReturns:\n * The AClock object", "examples": [], "file": "Source/AClock.spoon//init.lua", - "lineno": "97", + "lineno": "111", "name": "show", "notes": [], "parameters": [ @@ -70,7 +70,7 @@ "doc": "Show AClock for 4 seconds. If already showing, hide it.\n\nParameters:\n * None", "examples": [], "file": "Source/AClock.spoon//init.lua", - "lineno": "133", + "lineno": "147", "name": "toggleShow", "notes": [], "parameters": [ @@ -87,7 +87,7 @@ "doc": "Show AClock. If already showing, hide it.\n\nParameters:\n * None", "examples": [], "file": "Source/AClock.spoon//init.lua", - "lineno": "154", + "lineno": "168", "name": "toggleShowPersistent", "notes": [], "parameters": [ @@ -109,7 +109,7 @@ "doc": "Hide AClock.\n\nParameters:\n * None\n\nReturns:\n * The AClock object", "examples": [], "file": "Source/AClock.spoon//init.lua", - "lineno": "116", + "lineno": "130", "name": "hide", "notes": [], "parameters": [ @@ -147,7 +147,7 @@ "doc": "Show AClock.\n\nParameters:\n * None\n\nReturns:\n * The AClock object", "examples": [], "file": "Source/AClock.spoon//init.lua", - "lineno": "97", + "lineno": "111", "name": "show", "notes": [], "parameters": [ @@ -166,7 +166,7 @@ "doc": "Show AClock for 4 seconds. If already showing, hide it.\n\nParameters:\n * None", "examples": [], "file": "Source/AClock.spoon//init.lua", - "lineno": "133", + "lineno": "147", "name": "toggleShow", "notes": [], "parameters": [ @@ -183,7 +183,7 @@ "doc": "Show AClock. If already showing, hide it.\n\nParameters:\n * None", "examples": [], "file": "Source/AClock.spoon//init.lua", - "lineno": "154", + "lineno": "168", "name": "toggleShowPersistent", "notes": [], "parameters": [ From 5cbfe7d95bc58fd46e94d9904160acaa8acd22bd Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:21:14 +0000 Subject: [PATCH 38/55] Add binary package for AClock. --- Spoons/AClock.spoon.zip | Bin 2544 -> 2623 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Spoons/AClock.spoon.zip b/Spoons/AClock.spoon.zip index 93bf3b599222d6bb14eb5f94179232c2f3ca79bd..242cf59ef04f9d4ce87ac1ae4933d53166ddd1bc 100644 GIT binary patch literal 2623 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 TX4|{_N6^mX+^Me Date: Wed, 7 Aug 2024 13:21:15 +0000 Subject: [PATCH 39/55] Update docs --- docs/AClock.html | 8 ++++---- docs/docs.json | 16 ++++++++-------- docs/templated_docs.json | 16 ++++++++-------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/AClock.html b/docs/AClock.html index ac175efa..2e898afe 100644 --- a/docs/AClock.html +++ b/docs/AClock.html @@ -75,7 +75,7 @@
hide
Source - Source/AClock.spoon/init.lua line 116 + Source/AClock.spoon/init.lua line 130 @@ -149,7 +149,7 @@
show
Source - Source/AClock.spoon/init.lua line 97 + Source/AClock.spoon/init.lua line 111 @@ -183,7 +183,7 @@
toggleShow
Source - Source/AClock.spoon/init.lua line 133 + Source/AClock.spoon/init.lua line 147 @@ -217,7 +217,7 @@
toggleShowPersistent
Source - Source/AClock.spoon/init.lua line 154 + Source/AClock.spoon/init.lua line 168 diff --git a/docs/docs.json b/docs/docs.json index 2c2ad770..0e487cf5 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -13,7 +13,7 @@ "doc": "Hide AClock.\n\nParameters:\n * None\n\nReturns:\n * The AClock object", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "116", + "lineno": "130", "name": "hide", "notes": [], "parameters": [ @@ -51,7 +51,7 @@ "doc": "Show AClock.\n\nParameters:\n * None\n\nReturns:\n * The AClock object", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "97", + "lineno": "111", "name": "show", "notes": [], "parameters": [ @@ -70,7 +70,7 @@ "doc": "Show AClock for 4 seconds. If already showing, hide it.\n\nParameters:\n * None", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "133", + "lineno": "147", "name": "toggleShow", "notes": [], "parameters": [ @@ -87,7 +87,7 @@ "doc": "Show AClock. If already showing, hide it.\n\nParameters:\n * None", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "154", + "lineno": "168", "name": "toggleShowPersistent", "notes": [], "parameters": [ @@ -109,7 +109,7 @@ "doc": "Hide AClock.\n\nParameters:\n * None\n\nReturns:\n * The AClock object", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "116", + "lineno": "130", "name": "hide", "notes": [], "parameters": [ @@ -147,7 +147,7 @@ "doc": "Show AClock.\n\nParameters:\n * None\n\nReturns:\n * The AClock object", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "97", + "lineno": "111", "name": "show", "notes": [], "parameters": [ @@ -166,7 +166,7 @@ "doc": "Show AClock for 4 seconds. If already showing, hide it.\n\nParameters:\n * None", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "133", + "lineno": "147", "name": "toggleShow", "notes": [], "parameters": [ @@ -183,7 +183,7 @@ "doc": "Show AClock. If already showing, hide it.\n\nParameters:\n * None", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "154", + "lineno": "168", "name": "toggleShowPersistent", "notes": [], "parameters": [ diff --git a/docs/templated_docs.json b/docs/templated_docs.json index d9a7e22b..053d22f8 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -16,7 +16,7 @@ "doc_gfm": "

Hide AClock.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The AClock object
  • \n
\n", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "116", + "lineno": "130", "name": "hide", "notes": [], "notes_gfm": "", @@ -66,7 +66,7 @@ "doc_gfm": "

Show AClock.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The AClock object
  • \n
\n", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "97", + "lineno": "111", "name": "show", "notes": [], "notes_gfm": "", @@ -91,7 +91,7 @@ "doc_gfm": "

Show AClock for 4 seconds. If already showing, hide it.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "133", + "lineno": "147", "name": "toggleShow", "notes": [], "notes_gfm": "", @@ -114,7 +114,7 @@ "doc_gfm": "

Show AClock. If already showing, hide it.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "154", + "lineno": "168", "name": "toggleShowPersistent", "notes": [], "notes_gfm": "", @@ -144,7 +144,7 @@ "doc_gfm": "

Hide AClock.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The AClock object
  • \n
\n", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "116", + "lineno": "130", "name": "hide", "notes": [], "notes_gfm": "", @@ -194,7 +194,7 @@ "doc_gfm": "

Show AClock.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The AClock object
  • \n
\n", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "97", + "lineno": "111", "name": "show", "notes": [], "notes_gfm": "", @@ -219,7 +219,7 @@ "doc_gfm": "

Show AClock for 4 seconds. If already showing, hide it.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "133", + "lineno": "147", "name": "toggleShow", "notes": [], "notes_gfm": "", @@ -242,7 +242,7 @@ "doc_gfm": "

Show AClock. If already showing, hide it.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/AClock.spoon/init.lua", - "lineno": "154", + "lineno": "168", "name": "toggleShowPersistent", "notes": [], "notes_gfm": "", From ac6caa20ce69ce34ad75b9404432d820971a4589 Mon Sep 17 00:00:00 2001 From: Michael Mogenson <900731+mogenson@users.noreply.github.com> Date: Wed, 7 Aug 2024 09:31:09 -0400 Subject: [PATCH 40/55] Add PaperWM.spoon (#304) This is a scrolling tiled window manager. It provides mostly the same functionality for MacOS as the PaperWM Gnome extension does for Linux. Myself and a small group of people have been using this Spoon daily at https://github.com/mogenson/PaperWM.spoon for awhile. I think it has reached enough stability to be incorporated into the offical Hammerspoon Spoons repo. --- Source/PaperWM.spoon/init.lua | 1176 +++++++++++++++++++++++++++++++++ 1 file changed, 1176 insertions(+) create mode 100644 Source/PaperWM.spoon/init.lua diff --git a/Source/PaperWM.spoon/init.lua b/Source/PaperWM.spoon/init.lua new file mode 100644 index 00000000..819b9be2 --- /dev/null +++ b/Source/PaperWM.spoon/init.lua @@ -0,0 +1,1176 @@ +--- === PaperWM === +--- +--- A scrolling window manager. Inspired by PaperWM Gnome extension. +--- +--- # Usage +--- +--- `PaperWM:start()` will begin automatically tiling new and existing windows. +--- `PaperWM:stop()` will release control over windows. +--- `PaperWM::bindHotkeys()` will move / resize windows using keyboard shortcuts. +--- +--- Here is an example Hammerspoon config: +--- +--- ``` +--- PaperWM = hs.loadSpoon("PaperWM") +--- PaperWM:bindHotkeys({ +--- -- switch to a new focused window in tiled grid +--- focus_left = {{"ctrl", "alt", "cmd"}, "left"}, +--- focus_right = {{"ctrl", "alt", "cmd"}, "right"}, +--- focus_up = {{"ctrl", "alt", "cmd"}, "up"}, +--- focus_down = {{"ctrl", "alt", "cmd"}, "down"}, +--- +--- -- move windows around in tiled grid +--- swap_left = {{"ctrl", "alt", "cmd", "shift"}, "left"}, +--- swap_right = {{"ctrl", "alt", "cmd", "shift"}, "right"}, +--- swap_up = {{"ctrl", "alt", "cmd", "shift"}, "up"}, +--- swap_down = {{"ctrl", "alt", "cmd", "shift"}, "down"}, +--- +--- -- position and resize focused window +--- center_window = {{"ctrl", "alt", "cmd"}, "c"}, +--- full_width = {{"ctrl", "alt", "cmd"}, "f"}, +--- cycle_width = {{"ctrl", "alt", "cmd"}, "r"}, +--- cycle_height = {{"ctrl", "alt", "cmd", "shift"}, "r"}, +--- +--- -- move focused window into / out of a column +--- slurp_in = {{"ctrl", "alt", "cmd"}, "i"}, +--- barf_out = {{"ctrl", "alt", "cmd"}, "o"}, +--- +--- -- switch to a new Mission Control space +--- switch_space_1 = {{"ctrl", "alt", "cmd"}, "1"}, +--- switch_space_2 = {{"ctrl", "alt", "cmd"}, "2"}, +--- switch_space_3 = {{"ctrl", "alt", "cmd"}, "3"}, +--- switch_space_4 = {{"ctrl", "alt", "cmd"}, "4"}, +--- switch_space_5 = {{"ctrl", "alt", "cmd"}, "5"}, +--- switch_space_6 = {{"ctrl", "alt", "cmd"}, "6"}, +--- switch_space_7 = {{"ctrl", "alt", "cmd"}, "7"}, +--- switch_space_8 = {{"ctrl", "alt", "cmd"}, "8"}, +--- switch_space_9 = {{"ctrl", "alt", "cmd"}, "9"}, +--- +--- -- move focused window to a new space and tile +--- move_window_1 = {{"ctrl", "alt", "cmd", "shift"}, "1"}, +--- move_window_2 = {{"ctrl", "alt", "cmd", "shift"}, "2"}, +--- move_window_3 = {{"ctrl", "alt", "cmd", "shift"}, "3"}, +--- move_window_4 = {{"ctrl", "alt", "cmd", "shift"}, "4"}, +--- move_window_5 = {{"ctrl", "alt", "cmd", "shift"}, "5"}, +--- move_window_6 = {{"ctrl", "alt", "cmd", "shift"}, "6"}, +--- move_window_7 = {{"ctrl", "alt", "cmd", "shift"}, "7"}, +--- move_window_8 = {{"ctrl", "alt", "cmd", "shift"}, "8"}, +--- move_window_9 = {{"ctrl", "alt", "cmd", "shift"}, "9"} +--- }) +--- PaperWM:start() +--- ``` +--- +--- Use `PaperWM:bindHotkeys(PaperWM.default_hotkeys)` for defaults. +--- +--- Set `PaperWM.window_gap` to the number of pixels to space between windows and +--- the top and bottom screen edges. +--- +--- Overwrite `PaperWM.window_filter` to ignore specific applications. For example: +--- +--- ``` +--- PaperWM.window_filter = PaperWM.window_filter:setAppFilter("Finder", false) +--- PaperWM:start() -- restart for new window filter to take effect +--- ``` +--- +--- # Limitations +--- +--- Under System Preferences -> Mission Control, unselect "Automatically +--- rearrange Spaces based on most recent use" and select "Displays have separate +--- Spaces". +--- +--- MacOS does not allow a window to be moved fully off-screen. Windows that would-- +--- be tiled off-screen are placed in a margin on the left and right edge of the +--- screen. They are still visible and clickable. +--- +--- It's difficult to detect when a window is dragged from one space or screen to +--- another. Use the move_window_N commands to move windows between spaces and +--- screens. +--- +--- Arrange screens vertically to prevent windows from bleeding into other screens. +--- +--- +--- Download: [https://github.com/mogenson/PaperWM.spoon](https://github.com/mogenson/PaperWM.spoon) +local WindowFilter = hs.window.filter +local Window = hs.window +local Spaces = hs.spaces +local Screen = hs.screen +local DoAfter = hs.timer.doAfter +local Rect = hs.geometry.rect +local Watcher = hs.uielement.watcher + +local PaperWM = {} +PaperWM.__index = PaperWM + +-- Metadata +PaperWM.name = "PaperWM" +PaperWM.version = "0.4" +PaperWM.author = "Michael Mogenson" +PaperWM.homepage = "https://github.com/mogenson/PaperWM.spoon" +PaperWM.license = "MIT - https://opensource.org/licenses/MIT" + +--- PaperWM.default_hotkeys +--- Variable +--- Default hotkeys for moving / resizing windows +PaperWM.default_hotkeys = { + stop_events = { { "ctrl", "alt", "cmd", "shift" }, "q" }, + focus_left = { { "ctrl", "alt", "cmd" }, "left" }, + focus_right = { { "ctrl", "alt", "cmd" }, "right" }, + focus_up = { { "ctrl", "alt", "cmd" }, "up" }, + focus_down = { { "ctrl", "alt", "cmd" }, "down" }, + swap_left = { { "ctrl", "alt", "cmd", "shift" }, "left" }, + swap_right = { { "ctrl", "alt", "cmd", "shift" }, "right" }, + swap_up = { { "ctrl", "alt", "cmd", "shift" }, "up" }, + swap_down = { { "ctrl", "alt", "cmd", "shift" }, "down" }, + center_window = { { "ctrl", "alt", "cmd" }, "c" }, + full_width = { { "ctrl", "alt", "cmd" }, "f" }, + cycle_width = { { "ctrl", "alt", "cmd" }, "r" }, + cycle_height = { { "ctrl", "alt", "cmd", "shift" }, "r" }, + slurp_in = { { "ctrl", "alt", "cmd" }, "i" }, + barf_out = { { "ctrl", "alt", "cmd" }, "o" }, + switch_space_1 = { { "ctrl", "alt", "cmd" }, "1" }, + switch_space_2 = { { "ctrl", "alt", "cmd" }, "2" }, + switch_space_3 = { { "ctrl", "alt", "cmd" }, "3" }, + switch_space_4 = { { "ctrl", "alt", "cmd" }, "4" }, + switch_space_5 = { { "ctrl", "alt", "cmd" }, "5" }, + switch_space_6 = { { "ctrl", "alt", "cmd" }, "6" }, + switch_space_7 = { { "ctrl", "alt", "cmd" }, "7" }, + switch_space_8 = { { "ctrl", "alt", "cmd" }, "8" }, + switch_space_9 = { { "ctrl", "alt", "cmd" }, "9" }, + move_window_1 = { { "ctrl", "alt", "cmd", "shift" }, "1" }, + move_window_2 = { { "ctrl", "alt", "cmd", "shift" }, "2" }, + move_window_3 = { { "ctrl", "alt", "cmd", "shift" }, "3" }, + move_window_4 = { { "ctrl", "alt", "cmd", "shift" }, "4" }, + move_window_5 = { { "ctrl", "alt", "cmd", "shift" }, "5" }, + move_window_6 = { { "ctrl", "alt", "cmd", "shift" }, "6" }, + move_window_7 = { { "ctrl", "alt", "cmd", "shift" }, "7" }, + move_window_8 = { { "ctrl", "alt", "cmd", "shift" }, "8" }, + move_window_9 = { { "ctrl", "alt", "cmd", "shift" }, "9" } +} + +--- PaperWM.window_filter +--- Variable +--- Windows captured by this filter are automatically tiled and managed +PaperWM.window_filter = WindowFilter.new():setOverrideFilter({ + visible = true, + fullscreen = false, + hasTitlebar = true, + allowRoles = "AXStandardWindow" +}) + +--- PaperWM.window_gap +--- Variable +--- Number of pixels between tiled windows +PaperWM.window_gap = 8 + +--- PaperWM.logger +--- Variable +--- Logger object. Can be accessed to set default log level. +PaperWM.logger = hs.logger.new(PaperWM.name) + +-- constants +local Direction = { + LEFT = -1, + RIGHT = 1, + UP = -2, + DOWN = 2, + WIDTH = 3, + HEIGHT = 4 +} + +-- array of windows sorted from left to right +local window_list = {} -- 3D array of tiles in order of [space][x][y] +local index_table = {} -- dictionary of {space, x, y} with window id for keys +local ui_watchers = {} -- dictionary of uielement watchers with window id for keys + +-- current focused window +local focused_window = nil + +local function getSpace(index) + local layout = Spaces.allSpaces() + for _, screen in ipairs(Screen.allScreens()) do + local screen_uuid = screen:getUUID() + local num_spaces = #layout[screen_uuid] + if num_spaces >= index then return layout[screen_uuid][index] end + index = index - num_spaces + end +end + +local function getFirstVisibleWindow(columns, screen) + local x = screen:frame().x + for _, windows in ipairs(columns or {}) do + local window = windows[1] -- take first window in column + if window:frame().x >= x then return window end + end +end + +local function getColumn(space, col) return (window_list[space] or {})[col] end + +local function getWindow(space, col, row) + return (getColumn(space, col) or {})[row] +end + +local function getCanvas(screen) + local screen_frame = screen:frame() + return Rect(screen_frame.x + PaperWM.window_gap, + screen_frame.y + PaperWM.window_gap, + screen_frame.w - (2 * PaperWM.window_gap), + screen_frame.h - (2 * PaperWM.window_gap)) +end + +local function updateIndexTable(space, column) + local columns = window_list[space] or {} + for col = column, #columns do + for row, window in ipairs(getColumn(space, col)) do + index_table[window:id()] = { space = space, col = col, row = row } + end + end +end + +local pending_window = nil +local function windowEventHandler(window, event, self) + self.logger.df("%s for %s", event, window) + local space = nil + + --[[ When a new window is created, We first get a windowVisible event but + without a Space. Next we receive a windowFocused event for the window, but + this also sometimes lacks a Space. Our approach is to store the window + pending a Space in the pending_window variable and set a timer to try to add + the window again later. Also schedule the windowFocused handler to run later + after the window was added ]] + -- + + if event == "windowFocused" then + if pending_window and window == pending_window then + DoAfter(Window.animationDuration, + function() + windowEventHandler(window, event, self) + end) + return + end + focused_window = window + space = Spaces.windowSpaces(window)[1] + elseif event == "windowVisible" or event == "windowUnfullscreened" then + space = self:addWindow(window) + if pending_window and window == pending_window then + pending_window = nil -- tried to add window for the second time + elseif not space then + pending_window = window + DoAfter(Window.animationDuration, + function() + windowEventHandler(window, event, self) + end) + return + end + elseif event == "windowNotVisible" then + self:removeWindow(window) -- destroyed windows don't have a space + elseif event == "windowFullscreened" then + space = self:removeWindow(window, true) -- don't focus new window if fullscreened + elseif event == "AXWindowMoved" or event == "AXWindowResized" then + space = Spaces.windowSpaces(window)[1] + end + + if space then self:tileSpace(space) end +end + +--- PaperWM.bindHotkeys(mapping) +--- Method +--- Binds hotkeys for PaperWM +--- +--- Parameters: +--- * mapping - A table containing hotkey modifer/key details for the following items: +--- * stop_events - Stop automatic tiling +--- * focus_left - Focus window to left of current window +--- * focus_right - Focus window to right of current window +--- * focus_up - Focus window to up of current window +--- * focus_down - Focus window to down of current window +--- * swap_left - Swap positions of window to the left and current window +--- * swap_right - Swap positions of window to the right and current window +--- * swap_up - Swap positions of window above and current window +--- * swap_down - Swap positions of window below and current window +--- * center_window - Move current window to center of screen +--- * full_width - Resize width of current window to width of screen +--- * cycle_width - Toggle through preset window widths +--- * cycle_height - Toggle through preset window heights +--- * slurp_in - Move current window into column to the left +--- * barf_out - Remove current window from column and place to the right +--- * switch_space_1 - Switch to Mission Control space 1 +--- * switch_space_2 - Switch to Mission Control space 2 +--- * switch_space_3 - Switch to Mission Control space 3 +--- * switch_space_4 - Switch to Mission Control space 4 +--- * switch_space_5 - Switch to Mission Control space 5 +--- * switch_space_6 - Switch to Mission Control space 6 +--- * switch_space_7 - Switch to Mission Control space 7 +--- * switch_space_8 - Switch to Mission Control space 8 +--- * switch_space_9 - Switch to Mission Control space 9 +--- * move_window_1 - Move current window to Mission Control space 1 +--- * move_window_2 - Move current window to Mission Control space 2 +--- * move_window_3 - Move current window to Mission Control space 3 +--- * move_window_4 - Move current window to Mission Control space 4 +--- * move_window_5 - Move current window to Mission Control space 5 +--- * move_window_6 - Move current window to Mission Control space 6 +--- * move_window_7 - Move current window to Mission Control space 7 +--- * move_window_8 - Move current window to Mission Control space 8 +--- * move_window_9 - Move current window to Mission Control space 9 +function PaperWM:bindHotkeys(mapping) + local partial = hs.fnutils.partial + local spec = { + stop_events = partial(self.stop, self), + focus_left = partial(self.focusWindow, self, Direction.LEFT), + focus_right = partial(self.focusWindow, self, Direction.RIGHT), + focus_up = partial(self.focusWindow, self, Direction.UP), + focus_down = partial(self.focusWindow, self, Direction.DOWN), + swap_left = partial(self.swapWindows, self, Direction.LEFT), + swap_right = partial(self.swapWindows, self, Direction.RIGHT), + swap_up = partial(self.swapWindows, self, Direction.UP), + swap_down = partial(self.swapWindows, self, Direction.DOWN), + center_window = partial(self.centerWindow, self), + full_width = partial(self.setWindowFullWidth, self), + cycle_width = partial(self.cycleWindowSize, self, Direction.WIDTH), + cycle_height = partial(self.cycleWindowSize, self, Direction.HEIGHT), + slurp_in = partial(self.slurpWindow, self), + barf_out = partial(self.barfWindow, self), + switch_space_1 = partial(self.switchToSpace, self, 1), + switch_space_2 = partial(self.switchToSpace, self, 2), + switch_space_3 = partial(self.switchToSpace, self, 3), + switch_space_4 = partial(self.switchToSpace, self, 4), + switch_space_5 = partial(self.switchToSpace, self, 5), + switch_space_6 = partial(self.switchToSpace, self, 6), + switch_space_7 = partial(self.switchToSpace, self, 7), + switch_space_8 = partial(self.switchToSpace, self, 8), + switch_space_9 = partial(self.switchToSpace, self, 9), + move_window_1 = partial(self.moveWindowToSpace, self, 1), + move_window_2 = partial(self.moveWindowToSpace, self, 2), + move_window_3 = partial(self.moveWindowToSpace, self, 3), + move_window_4 = partial(self.moveWindowToSpace, self, 4), + move_window_5 = partial(self.moveWindowToSpace, self, 5), + move_window_6 = partial(self.moveWindowToSpace, self, 6), + move_window_7 = partial(self.moveWindowToSpace, self, 7), + move_window_8 = partial(self.moveWindowToSpace, self, 8), + move_window_9 = partial(self.moveWindowToSpace, self, 9) + } + hs.spoons.bindHotkeysToSpec(spec, mapping) +end + +--- PaperWM:start() +--- Method +--- Start automatic tiling of windows +--- +--- Parameters: +--- * None +--- +--- Returns: +--- * The PaperWM object +function PaperWM:start() + -- check for some settings + if not Spaces.screensHaveSeparateSpaces() then + self.logger.e( + "please check 'Displays have separate Spaces' in System Preferences -> Mission Control") + end + + -- clear state + window_list = {} + index_table = {} + ui_watchers = {} + + -- populate window list, index table, and ui_watchers + self:refreshWindows() + + -- set initial layout + for space, _ in pairs(window_list) do self:tileSpace(space) end + + -- listen for window events + self.window_filter:subscribe({ + WindowFilter.windowFocused, WindowFilter.windowVisible, + WindowFilter.windowNotVisible, WindowFilter.windowFullscreened, + WindowFilter.windowUnfullscreened + }, function(window, _, event) windowEventHandler(window, event, self) end) + + return self +end + +--- PaperWM:stop() +--- Method +--- Stop automatic tiling of windows +--- +--- Parameters: +--- * None +--- +--- Returns: +--- * The PaperWM object +function PaperWM:stop() + -- stop events + self.window_filter:unsubscribeAll() + for _, watcher in pairs(ui_watchers) do watcher:stop() end + + return self +end + +--- PaperWM:tileColumn(windows, bounds, h, w, id, h4id) +--- Method +--- Tile a column of windows +--- +--- Parameters: +--- * windows - A list of hs.windows. +--- * bounds - An hs.geometry.rect. The area for this column to fill. +--- * h - The height for each window in column. +--- * w - The width for each window in column. +--- * id - A hs.window.id() for a specific window in column. +--- * h4id - The height for a window matching id in column. +--- +--- Notes: +--- * The h, w, id, and h4id parameters are optional. The height and width of +--- all windows will be calculated and set to fill column bounds. +--- * If bounds width is not specified, all windows in column will be resized +--- to width of first window. +--- +--- Returns: +--- * The width of the column +function PaperWM:tileColumn(windows, bounds, h, w, id, h4id) + local last_window, frame + for _, window in ipairs(windows) do + frame = window:frame() + w = w or frame.w -- take given width or width of first window + if bounds.x then -- set either left or right x coord + frame.x = bounds.x + elseif bounds.x2 then + frame.x = bounds.x2 - w + end + if h then -- set height if given + if id and h4id and window:id() == id then + frame.h = h4id -- use this height for window with id + else + frame.h = h -- use this height for all other windows + end + end + frame.y = bounds.y + frame.w = w + frame.y2 = math.min(frame.y2, bounds.y2) -- don't overflow bottom of bounds + self:moveWindow(window, frame) + bounds.y = math.min(frame.y2 + self.window_gap, bounds.y2) + last_window = window + end + -- expand last window height to bottom + if frame.y2 ~= bounds.y2 then + frame.y2 = bounds.y2 + self:moveWindow(last_window, frame) + end + return w -- return width of column +end + +--- PaperWM:tileSpace(space) +--- Method +--- Tile all windows within a space +--- +--- Parameters: +--- * space - A hs.spaces space. +function PaperWM:tileSpace(space) + -- MacOS doesn't allow windows to be moved off screen + -- stack windows in a visible margin on either side + local screen_margin = 40 + + if not space or Spaces.spaceType(space) ~= "user" then + self.logger.e("current space invalid") + return + end + + -- find screen for space + local screen = Screen(Spaces.spaceDisplay(space)) + if not screen then + self.logger.e("no screen for space") + return + end + + -- if focused window is in space, tile from that + focused_window = focused_window or Window.focusedWindow() + local anchor_window = (focused_window and + (Spaces.windowSpaces(focused_window)[1] == space)) and + focused_window or + getFirstVisibleWindow(window_list[space], screen) + + if not anchor_window then + self.logger.e("no anchor window in space") + return + end + + local anchor_index = index_table[anchor_window:id()] + if not anchor_index then + self.logger.e("anchor index not found") + if self:addWindow(anchor_window) == space then + self.logger.d("added missing window") + anchor_index = index_table[anchor_window:id()] + else + return -- bail + end + end + + -- get some global coordinates + local screen_frame = screen:frame() + local left_margin = screen_frame.x + screen_margin + local right_margin = screen_frame.x2 - screen_margin + local canvas = getCanvas(screen) + + -- make sure anchor window is on screen + local anchor_frame = anchor_window:frame() + anchor_frame.x = math.max(anchor_frame.x, canvas.x) + anchor_frame.w = math.min(anchor_frame.w, canvas.w) + anchor_frame.h = math.min(anchor_frame.h, canvas.h) + if anchor_frame.x2 > canvas.x2 then + anchor_frame.x = canvas.x2 - anchor_frame.w + end + + -- adjust anchor window column + local column = getColumn(space, anchor_index.col) + if not column then + self.logger.e("no anchor window column") + return + end + + -- TODO: need a minimum window height + if #column == 1 then + anchor_frame.y, anchor_frame.h = canvas.y, canvas.h + self:moveWindow(anchor_window, anchor_frame) + else + local n = #column - 1 -- number of other windows in column + local h = + math.max(0, canvas.h - anchor_frame.h - (n * self.window_gap)) // n + local bounds = { + x = anchor_frame.x, + x2 = nil, + y = canvas.y, + y2 = canvas.y2 + } + self:tileColumn(column, bounds, h, anchor_frame.w, anchor_window:id(), + anchor_frame.h) + end + + -- tile windows from anchor right + local x = math.min(anchor_frame.x2 + self.window_gap, right_margin) + for col = anchor_index.col + 1, #(window_list[space] or {}) do + local bounds = { x = x, x2 = nil, y = canvas.y, y2 = canvas.y2 } + local column_width = self:tileColumn(getColumn(space, col), bounds) + x = math.min(x + column_width + self.window_gap, right_margin) + end + + -- tile windows from anchor left + local x2 = math.max(anchor_frame.x - self.window_gap, left_margin) + for col = anchor_index.col - 1, 1, -1 do + local bounds = { x = nil, x2 = x2, y = canvas.y, y2 = canvas.y2 } + local column_width = self:tileColumn(getColumn(space, col), bounds) + x2 = math.max(x2 - column_width - self.window_gap, left_margin) + end +end + +--- PaperWM:refreshWindows() +--- Method +--- Searches for all windows that match window filter. +--- +--- Parameters: +--- * None +--- +--- Returns: +--- * A boolean, true if the layout needs to be re-tiled, false if no change. +function PaperWM:refreshWindows() + -- get all windows across spaces + local all_windows = self.window_filter:getWindows() + + local refresh_needed = false + for _, window in ipairs(all_windows) do + local index = index_table[window:id()] + if not index then + -- add window + self:addWindow(window) + refresh_needed = true + elseif index.space ~= Spaces.windowSpaces(window)[1] then + -- move to window list in new space + self:removeWindow(window) + self:addWindow(window) + refresh_needed = true + end + end + + return refresh_needed +end + +--- PaperWM:addWindow(add_window) +--- Method +--- Adds a window to layout and tiles. +--- +--- Parameters: +--- * add_window - An hs.window +--- +--- Returns: +--- * The hs.spaces space for added window or nil if window not added. +function PaperWM:addWindow(add_window) + -- check if window is already in window list + if index_table[add_window:id()] then return end + + local space = Spaces.windowSpaces(add_window)[1] + if not space then + self.logger.e("add window does not have a space") + return + end + if not window_list[space] then window_list[space] = {} end + + -- find where to insert window + local add_column = 1 + + -- when addWindow() is called from a window created event: + -- focused_window from previous window focused event will not be add_window + -- hs.window.focusedWindow() will return add_window + -- new window focused event for add_window has not happened yet + if focused_window and + ((index_table[focused_window:id()] or {}).space == space) and + (focused_window:id() ~= add_window:id()) then + add_column = index_table[focused_window:id()].col + 1 -- insert to the right + else + local x = add_window:frame().center.x + for col, windows in ipairs(window_list[space]) do + if x < windows[1]:frame().center.x then + add_column = col + break + end + end + end + + -- add window + table.insert(window_list[space], add_column, { add_window }) + + -- update index table + updateIndexTable(space, add_column) + + -- subscribe to window moved events + local watcher = add_window:newWatcher( + function(window, event, _, self) + windowEventHandler(window, event, self) + end, self) + watcher:start({ Watcher.windowMoved, Watcher.windowResized }) + ui_watchers[add_window:id()] = watcher + + return space +end + +--- PaperWM:remove_window(remove_window, skip_new_window_focus) +--- Method +--- Remove window from tiling layout +--- +--- Parameters: +--- * remove_window - A hs.window to remove from tiling layout +--- * skip_new_window_focus - A boolean. True if a nearby window should not be +--- focused after current window is removed. +--- +--- Returns: +--- * The hs.spaces space for removed window. +function PaperWM:removeWindow(remove_window, skip_new_window_focus) + -- get index of window + local remove_index = index_table[remove_window:id()] + if not remove_index then + self.logger.e("remove index not found") + return + end + + if not skip_new_window_focus then -- find nearby window to focus + for _, direction in ipairs({ + Direction.DOWN, Direction.UP, Direction.LEFT, Direction.RIGHT + }) do if self:focusWindow(direction, remove_index) then break end end + end + + -- remove window + table.remove(window_list[remove_index.space][remove_index.col], + remove_index.row) + if #window_list[remove_index.space][remove_index.col] == 0 then + table.remove(window_list[remove_index.space], remove_index.col) + end + + -- remove watcher + ui_watchers[remove_window:id()] = nil + + -- update index table + index_table[remove_window:id()] = nil + updateIndexTable(remove_index.space, remove_index.col) + + -- remove if space is empty + if #window_list[remove_index.space] == 0 then + window_list[remove_index.space] = nil + end + + return remove_index.space -- return space for removed window +end + +--- PaperWM:focusWindow(direction, focused_index) +--- Method +--- Change focus to a nearby window +--- +--- Parameters: +--- * direction - One of Direction { LEFT, RIGHT, DOWN, UP } +--- * focused_index - The coordinates of the current window in the tiling layout +--- +--- Returns: +--- * A boolean. True if a new window was focused. False if no nearby window +--- was found in that direction. +function PaperWM:focusWindow(direction, focused_index) + if not focused_index then + -- get current focused window + focused_window = focused_window or Window.focusedWindow() + if not focused_window then return false end + + -- get focused window index + focused_index = index_table[focused_window:id()] + end + + if not focused_index then + self.logger.e("focused index not found") + return false + end + + -- get new focused window + local new_focused_window + if direction == Direction.LEFT or direction == Direction.RIGHT then + -- walk down column, looking for match in neighbor column + for row = focused_index.row, 1, -1 do + new_focused_window = getWindow(focused_index.space, + focused_index.col + direction, row) + if new_focused_window then break end + end + elseif direction == Direction.UP or direction == Direction.DOWN then + new_focused_window = getWindow(focused_index.space, focused_index.col, + focused_index.row + (direction // 2)) + end + + if not new_focused_window then + self.logger.d("new focused window not found") + return false + end + + -- focus new window, windowFocused event will be emited immediately + new_focused_window:focus() + return true +end + +--- PaperWM:swapWindows(direction) +--- Method +--- Swaps window postions between current window and window in specified direction. +--- +--- Parameters: +--- * direction - One of Direction { LEFT, RIGHT, DOWN, UP } +function PaperWM:swapWindows(direction) + -- use focused window as source window + focused_window = focused_window or Window.focusedWindow() + if not focused_window then return end + + -- get focused window index + local focused_index = index_table[focused_window:id()] + if not focused_index then + self.logger.e("focused index not found") + return + end + + if direction == Direction.LEFT or direction == Direction.RIGHT then + -- get target windows + local target_index = { col = focused_index.col + direction } + local target_column = window_list[focused_index.space][target_index.col] + if not target_column then + self.logger.d("target column not found") + return + end + + -- swap place in window list + local focused_column = + window_list[focused_index.space][focused_index.col] + window_list[focused_index.space][target_index.col] = focused_column + window_list[focused_index.space][focused_index.col] = target_column + + -- update index table + for row, window in ipairs(target_column) do + index_table[window:id()] = { + space = focused_index.space, + col = focused_index.col, + row = row + } + end + for row, window in ipairs(focused_column) do + index_table[window:id()] = { + space = focused_index.space, + col = target_index.col, + row = row + } + end + + -- swap frames + local focused_frame = focused_window:frame() + local target_frame = target_column[1]:frame() + if direction == Direction.LEFT then + focused_frame.x = target_frame.x + target_frame.x = focused_frame.x2 + self.window_gap + else -- Direction.RIGHT + target_frame.x = focused_frame.x + focused_frame.x = target_frame.x2 + self.window_gap + end + for _, window in ipairs(target_column) do + local frame = window:frame() + frame.x = target_frame.x + self:moveWindow(window, frame) + end + for _, window in ipairs(focused_column) do + local frame = window:frame() + frame.x = focused_frame.x + self:moveWindow(window, frame) + end + elseif direction == Direction.UP or direction == Direction.DOWN then + -- get target window + local target_index = { + space = focused_index.space, + col = focused_index.col, + row = focused_index.row + (direction // 2) + } + local target_window = getWindow(target_index.space, target_index.col, + target_index.row) + if not target_window then + self.logger.d("target window not found") + return + end + + -- swap places in window list + window_list[target_index.space][target_index.col][target_index.row] = + focused_window + window_list[focused_index.space][focused_index.col][focused_index.row] = + target_window + + -- update index table + index_table[target_window:id()] = focused_index + index_table[focused_window:id()] = target_index + + -- swap frames + local focused_frame = focused_window:frame() + local target_frame = target_window:frame() + if direction == Direction.UP then + focused_frame.y = target_frame.y + target_frame.y = focused_frame.y2 + self.window_gap + else -- Direction.DOWN + target_frame.y = focused_frame.y + focused_frame.y = target_frame.y2 + self.window_gap + end + self:moveWindow(focused_window, focused_frame) + self:moveWindow(target_window, target_frame) + end + + -- update layout + self:tileSpace(focused_index.space) +end + +--- PaperWM:centerWindow() +--- Method +--- Moves current window to center of screen, without resizing. +--- +--- Parameters: +--- * None +function PaperWM:centerWindow() + -- get current focused window + focused_window = focused_window or Window.focusedWindow() + if not focused_window then return end + + -- get global coordinates + local focused_frame = focused_window:frame() + local screen_frame = focused_window:screen():frame() + + -- center window + focused_frame.x = screen_frame.x + (screen_frame.w // 2) - + (focused_frame.w // 2) + self:moveWindow(focused_window, focused_frame) + + -- update layout + local space = Spaces.windowSpaces(focused_window)[1] + self:tileSpace(space) +end + +--- PaperWM:setWindowFullWidth() +--- Method +--- Resizes current window's width to width of screen, without adjusting height. +--- +--- Parameters: +--- * None +function PaperWM:setWindowFullWidth() + -- get current focused window + focused_window = focused_window or Window.focusedWindow() + if not focused_window then return end + + -- fullscreen window width + local canvas = getCanvas(focused_window:screen()) + local focused_frame = focused_window:frame() + focused_frame.x, focused_frame.w = canvas.x, canvas.w + self:moveWindow(focused_window, focused_frame) + + -- update layout + local space = Spaces.windowSpaces(focused_window)[1] + self:tileSpace(space) +end + +--- PaperWM:cycleWindowSize(direction) +--- Method +--- Resizes current window by cycling through width or height ratios. +--- +--- Parameters: +--- * direction - One of Direction { WIDTH, HEIGHT } +function PaperWM:cycleWindowSize(direction) + -- get current focused window + focused_window = focused_window or Window.focusedWindow() + if not focused_window then return end + + local function findNewSize(area_size, frame_size) + -- calculate pixel widths from ratios + local sizes = { 0.38195, 0.5, 0.61804 } + for index, size in ipairs(sizes) do + sizes[index] = size * area_size + end + + -- find new size + local new_size = sizes[1] + for _, size in ipairs(sizes) do + if size > frame_size + 10 then + new_size = size + break + end + end + + return new_size + end + + local canvas = getCanvas(focused_window:screen()) + local focused_frame = focused_window:frame() + + if direction == Direction.WIDTH then + local new_width = findNewSize(canvas.w, focused_frame.w) + focused_frame.x = focused_frame.x + ((focused_frame.w - new_width) // 2) + focused_frame.w = new_width + elseif direction == Direction.HEIGHT then + local new_height = findNewSize(canvas.h, focused_frame.h) + focused_frame.y = math.max(canvas.y, focused_frame.y + + ((focused_frame.h - new_height) // 2)) + focused_frame.h = new_height + focused_frame.y = focused_frame.y - + math.max(0, focused_frame.y2 - canvas.y2) + end + + -- apply new size + self:moveWindow(focused_window, focused_frame) + + -- update layout + local space = Spaces.windowSpaces(focused_window)[1] + self:tileSpace(space) +end + +--- PaperWM:slurpWindow() +--- Method +--- Moves current window into column of windows to the left +--- +--- Parameters: +--- * None +function PaperWM:slurpWindow() + -- TODO paperwm behavior: + -- add top window from column to the right to bottom of current column + -- if no colum to the right and current window is only window in current column, + -- add current window to bottom of column to the left + + -- get current focused window + focused_window = focused_window or Window.focusedWindow() + if not focused_window then return end + + -- get window index + local focused_index = index_table[focused_window:id()] + if not focused_index then + self.logger.e("focused index not found") + return + end + + -- get column to left + local column = window_list[focused_index.space][focused_index.col - 1] + if not column then + self.logger.d("column not found") + return + end + + -- remove window + table.remove(window_list[focused_index.space][focused_index.col], + focused_index.row) + if #window_list[focused_index.space][focused_index.col] == 0 then + table.remove(window_list[focused_index.space], focused_index.col) + end + + -- append to end of column + table.insert(column, focused_window) + + -- update index table + local num_windows = #column + index_table[focused_window:id()] = { + space = focused_index.space, + col = focused_index.col - 1, + row = num_windows + } + updateIndexTable(focused_index.space, focused_index.col) + + -- adjust window frames + local canvas = getCanvas(focused_window:screen()) + local bounds = { + x = column[1]:frame().x, + x2 = nil, + y = canvas.y, + y2 = canvas.y2 + } + local h = math.max(0, canvas.h - ((num_windows - 1) * self.window_gap)) // + num_windows + self:tileColumn(column, bounds, h) + + -- update layout + self:tileSpace(focused_index.space) +end + +--- PaperWM:barfWindow() +--- Method +--- Removes current window from column and places it to the right +--- +--- Parameters: +--- * None +function PaperWM:barfWindow() + -- TODO paperwm behavior: + -- remove bottom window of current column + -- place window into a new column to the right-- + + -- get current focused window + focused_window = focused_window or Window.focusedWindow() + if not focused_window then return end + + -- get window index + local focused_index = index_table[focused_window:id()] + if not focused_index then + self.logger.e("focused index not found") + return + end + + -- get column + local column = window_list[focused_index.space][focused_index.col] + if #column == 1 then + self.logger.d("only window in column") + return + end + + -- remove window and insert in new column + table.remove(column, focused_index.row) + table.insert(window_list[focused_index.space], focused_index.col + 1, + { focused_window }) + + -- update index table + updateIndexTable(focused_index.space, focused_index.col) + + -- adjust window frames + local num_windows = #column + local canvas = getCanvas(focused_window:screen()) + local focused_frame = focused_window:frame() + local bounds = { x = focused_frame.x, x2 = nil, y = canvas.y, y2 = canvas.y2 } + local h = math.max(0, canvas.h - ((num_windows - 1) * self.window_gap)) // + num_windows + focused_frame.y = canvas.y + focused_frame.x = focused_frame.x2 + self.window_gap + focused_frame.h = canvas.h + self:moveWindow(focused_window, focused_frame) + self:tileColumn(column, bounds, h) + + -- update layout + self:tileSpace(focused_index.space) +end + +--- PaperWM:switchToSpace(index) +--- Method +--- Switch to a Mission Control space +--- +--- Parameters: +--- * index - The space number +function PaperWM:switchToSpace(index) + local space = getSpace(index) + if not space then + self.logger.d("space not found") + return + end + + Spaces.gotoSpace(space) +end + +--- PaperWM:moveWindowToSpace(index) +--- Method +--- Moves the current window to a new Mission Control space +--- +--- Parameters: +--- * index - The space number +function PaperWM:moveWindowToSpace(index) + focused_window = focused_window or Window.focusedWindow() + if not focused_window then + self.logger.d("focused window not found") + return + end + + local focused_index = index_table[focused_window:id()] + if not focused_index then + self.logger.e("focused index not found") + return + end + + local new_space = getSpace(index) + if not new_space then + self.logger.d("space not found") + return + end + + if Spaces.spaceType(new_space) ~= "user" then + self.logger.d("space is invalid") + return + end + + local screen = Screen(Spaces.spaceDisplay(new_space)) + if not screen then + self.logger.d("screen not found") + return + end + + -- cache a local copy, removeWindow() will clear global focused_window + local focused_window = focused_window + local old_space = self:removeWindow(focused_window) + if not old_space then + self.logger.e("can't remove focused window") + return + end + + Spaces.moveWindowToSpace(focused_window, new_space) + self:addWindow(focused_window) + self:tileSpace(old_space) + self:tileSpace(new_space) + Spaces.gotoSpace(new_space) +end + +--- PaperWM::moveWindow(window, frame) +--- Method +--- Resizes a window without triggering a windowMoved event +--- +--- Parameters: +--- * window - An hs.window +--- * frame - An hs.geometry.rect for the windows new frame size. +function PaperWM:moveWindow(window, frame) + -- greater than 0.017 hs.window animation step time + local padding = 0.02 + + local watcher = ui_watchers[window:id()] + if not watcher then + self.logger.e("window does not have ui watcher") + return + end + + if frame == window:frame() then + self.logger.v("no change in window frame") + return + end + + watcher:stop() + window:setFrame(frame) + DoAfter(Window.animationDuration + padding, function() + watcher:start({ Watcher.windowMoved, Watcher.windowResized }) + end) +end + +return PaperWM From b618da99c9da4c7564b35eab5b00781c72c09a0f Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:31:56 +0000 Subject: [PATCH 41/55] Generate docs for PaperWM --- Source/PaperWM.spoon/docs.json | 778 +++++++++++++++++++++++++++++++++ 1 file changed, 778 insertions(+) create mode 100644 Source/PaperWM.spoon/docs.json diff --git a/Source/PaperWM.spoon/docs.json b/Source/PaperWM.spoon/docs.json new file mode 100644 index 00000000..bf217ce8 --- /dev/null +++ b/Source/PaperWM.spoon/docs.json @@ -0,0 +1,778 @@ +[ + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "PaperWM:addWindow(add_window)", + "desc": "Adds a window to layout and tiles.", + "doc": "Adds a window to layout and tiles.\n\nParameters:\n * add_window - An hs.window\n\nReturns:\n * The hs.spaces space for added window or nil if window not added.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "594", + "name": "addWindow", + "notes": [], + "parameters": [ + " * add_window - An hs.window" + ], + "returns": [ + " * The hs.spaces space for added window or nil if window not added." + ], + "signature": "PaperWM:addWindow(add_window)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:barfWindow()", + "desc": "Removes current window from column and places it to the right", + "doc": "Removes current window from column and places it to the right\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "1026", + "name": "barfWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:barfWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.bindHotkeys(mapping)", + "desc": "Binds hotkeys for PaperWM", + "doc": "Binds hotkeys for PaperWM\n\nParameters:\n * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "275", + "name": "bindHotkeys", + "notes": [], + "parameters": [ + " * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9" + ], + "returns": [], + "signature": "PaperWM.bindHotkeys(mapping)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:centerWindow()", + "desc": "Moves current window to center of screen, without resizing.", + "doc": "Moves current window to center of screen, without resizing.\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "860", + "name": "centerWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:centerWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:cycleWindowSize(direction)", + "desc": "Resizes current window by cycling through width or height ratios.", + "doc": "Resizes current window by cycling through width or height ratios.\n\nParameters:\n * direction - One of Direction { WIDTH, HEIGHT }", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "907", + "name": "cycleWindowSize", + "notes": [], + "parameters": [ + " * direction - One of Direction { WIDTH, HEIGHT }" + ], + "returns": [], + "signature": "PaperWM:cycleWindowSize(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:focusWindow(direction, focused_index)", + "desc": "Change focus to a nearby window", + "doc": "Change focus to a nearby window\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }\n * focused_index - The coordinates of the current window in the tiling layout\n\nReturns:\n * A boolean. True if a new window was focused. False if no nearby window\n was found in that direction.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "699", + "name": "focusWindow", + "notes": [], + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + " * focused_index - The coordinates of the current window in the tiling layout" + ], + "returns": [ + " * A boolean. True if a new window was focused. False if no nearby window", + " was found in that direction." + ], + "signature": "PaperWM:focusWindow(direction, focused_index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM::moveWindow(window, frame)", + "desc": "Resizes a window without triggering a windowMoved event", + "doc": "Resizes a window without triggering a windowMoved event\n\nParameters:\n * window - An hs.window\n * frame - An hs.geometry.rect for the windows new frame size.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "1147", + "name": "moveWindow", + "notes": [], + "parameters": [ + " * window - An hs.window", + " * frame - An hs.geometry.rect for the windows new frame size." + ], + "returns": [], + "signature": "PaperWM::moveWindow(window, frame)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:moveWindowToSpace(index)", + "desc": "Moves the current window to a new Mission Control space", + "doc": "Moves the current window to a new Mission Control space\n\nParameters:\n * index - The space number", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "1096", + "name": "moveWindowToSpace", + "notes": [], + "parameters": [ + " * index - The space number" + ], + "returns": [], + "signature": "PaperWM:moveWindowToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:refreshWindows()", + "desc": "Searches for all windows that match window filter.", + "doc": "Searches for all windows that match window filter.\n\nParameters:\n * None\n\nReturns:\n * A boolean, true if the layout needs to be re-tiled, false if no change.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "563", + "name": "refreshWindows", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * A boolean, true if the layout needs to be re-tiled, false if no change." + ], + "signature": "PaperWM:refreshWindows()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "desc": "Remove window from tiling layout", + "doc": "Remove window from tiling layout\n\nParameters:\n * remove_window - A hs.window to remove from tiling layout\n * skip_new_window_focus - A boolean. True if a nearby window should not be\n focused after current window is removed.\n\nReturns:\n * The hs.spaces space for removed window.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "652", + "name": "remove_window", + "notes": [], + "parameters": [ + " * remove_window - A hs.window to remove from tiling layout", + " * skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed." + ], + "returns": [ + " * The hs.spaces space for removed window." + ], + "signature": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:setWindowFullWidth()", + "desc": "Resizes current window's width to width of screen, without adjusting height.", + "doc": "Resizes current window's width to width of screen, without adjusting height.\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "885", + "name": "setWindowFullWidth", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:setWindowFullWidth()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:slurpWindow()", + "desc": "Moves current window into column of windows to the left", + "doc": "Moves current window into column of windows to the left\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "961", + "name": "slurpWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:slurpWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:start()", + "desc": "Start automatic tiling of windows", + "doc": "Start automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "354", + "name": "start", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The PaperWM object" + ], + "signature": "PaperWM:start()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:stop()", + "desc": "Stop automatic tiling of windows", + "doc": "Stop automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "391", + "name": "stop", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The PaperWM object" + ], + "signature": "PaperWM:stop()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:swapWindows(direction)", + "desc": "Swaps window postions between current window and window in specified direction.", + "doc": "Swaps window postions between current window and window in specified direction.\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "749", + "name": "swapWindows", + "notes": [], + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }" + ], + "returns": [], + "signature": "PaperWM:swapWindows(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:switchToSpace(index)", + "desc": "Switch to a Mission Control space", + "doc": "Switch to a Mission Control space\n\nParameters:\n * index - The space number", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "1080", + "name": "switchToSpace", + "notes": [], + "parameters": [ + " * index - The space number" + ], + "returns": [], + "signature": "PaperWM:switchToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "desc": "Tile a column of windows", + "doc": "Tile a column of windows\n\nParameters:\n * windows - A list of hs.windows.\n * bounds - An hs.geometry.rect. The area for this column to fill.\n * h - The height for each window in column.\n * w - The width for each window in column.\n * id - A hs.window.id() for a specific window in column.\n * h4id - The height for a window matching id in column.\n\nNotes:\n * The h, w, id, and h4id parameters are optional. The height and width of\n all windows will be calculated and set to fill column bounds.\n * If bounds width is not specified, all windows in column will be resized\n to width of first window.\n\nReturns:\n * The width of the column", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "408", + "name": "tileColumn", + "notes": [ + " * The h, w, id, and h4id parameters are optional. The height and width of", + " all windows will be calculated and set to fill column bounds.", + " * If bounds width is not specified, all windows in column will be resized", + " to width of first window." + ], + "parameters": [ + " * windows - A list of hs.windows.", + " * bounds - An hs.geometry.rect. The area for this column to fill.", + " * h - The height for each window in column.", + " * w - The width for each window in column.", + " * id - A hs.window.id() for a specific window in column.", + " * h4id - The height for a window matching id in column." + ], + "returns": [ + " * The width of the column" + ], + "signature": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileSpace(space)", + "desc": "Tile all windows within a space", + "doc": "Tile all windows within a space\n\nParameters:\n * space - A hs.spaces space.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "460", + "name": "tileSpace", + "notes": [], + "parameters": [ + " * space - A hs.spaces space." + ], + "returns": [], + "signature": "PaperWM:tileSpace(space)", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [ + { + "def": "PaperWM.default_hotkeys", + "desc": "Default hotkeys for moving / resizing windows", + "doc": "Default hotkeys for moving / resizing windows", + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "111", + "name": "default_hotkeys", + "signature": "PaperWM.default_hotkeys", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.logger", + "desc": "Logger object. Can be accessed to set default log level.", + "doc": "Logger object. Can be accessed to set default log level.", + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "165", + "name": "logger", + "signature": "PaperWM.logger", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_filter", + "desc": "Windows captured by this filter are automatically tiled and managed", + "doc": "Windows captured by this filter are automatically tiled and managed", + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "150", + "name": "window_filter", + "signature": "PaperWM.window_filter", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_gap", + "desc": "Number of pixels between tiled windows", + "doc": "Number of pixels between tiled windows", + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "160", + "name": "window_gap", + "signature": "PaperWM.window_gap", + "stripped_doc": "", + "type": "Variable" + } + ], + "desc": "A scrolling window manager. Inspired by PaperWM Gnome extension.", + "doc": "A scrolling window manager. Inspired by PaperWM Gnome extension.\n\n# Usage\n\n`PaperWM:start()` will begin automatically tiling new and existing windows.\n`PaperWM:stop()` will release control over windows.\n`PaperWM::bindHotkeys()` will move / resize windows using keyboard shortcuts.\n\nHere is an example Hammerspoon config:\n\n```\nPaperWM = hs.loadSpoon(\"PaperWM\")\nPaperWM:bindHotkeys({\n -- switch to a new focused window in tiled grid\n focus_left = {{\"ctrl\", \"alt\", \"cmd\"}, \"left\"},\n focus_right = {{\"ctrl\", \"alt\", \"cmd\"}, \"right\"},\n focus_up = {{\"ctrl\", \"alt\", \"cmd\"}, \"up\"},\n focus_down = {{\"ctrl\", \"alt\", \"cmd\"}, \"down\"},\n\n -- move windows around in tiled grid\n swap_left = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"left\"},\n swap_right = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"right\"},\n swap_up = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"up\"},\n swap_down = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"down\"},\n\n -- position and resize focused window\n center_window = {{\"ctrl\", \"alt\", \"cmd\"}, \"c\"},\n full_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"f\"},\n cycle_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"r\"},\n cycle_height = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"r\"},\n\n -- move focused window into / out of a column\n slurp_in = {{\"ctrl\", \"alt\", \"cmd\"}, \"i\"},\n barf_out = {{\"ctrl\", \"alt\", \"cmd\"}, \"o\"},\n\n -- switch to a new Mission Control space\n switch_space_1 = {{\"ctrl\", \"alt\", \"cmd\"}, \"1\"},\n switch_space_2 = {{\"ctrl\", \"alt\", \"cmd\"}, \"2\"},\n switch_space_3 = {{\"ctrl\", \"alt\", \"cmd\"}, \"3\"},\n switch_space_4 = {{\"ctrl\", \"alt\", \"cmd\"}, \"4\"},\n switch_space_5 = {{\"ctrl\", \"alt\", \"cmd\"}, \"5\"},\n switch_space_6 = {{\"ctrl\", \"alt\", \"cmd\"}, \"6\"},\n switch_space_7 = {{\"ctrl\", \"alt\", \"cmd\"}, \"7\"},\n switch_space_8 = {{\"ctrl\", \"alt\", \"cmd\"}, \"8\"},\n switch_space_9 = {{\"ctrl\", \"alt\", \"cmd\"}, \"9\"},\n\n -- move focused window to a new space and tile\n move_window_1 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"1\"},\n move_window_2 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"2\"},\n move_window_3 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"3\"},\n move_window_4 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"4\"},\n move_window_5 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"5\"},\n move_window_6 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"6\"},\n move_window_7 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"7\"},\n move_window_8 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"8\"},\n move_window_9 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"9\"}\n})\nPaperWM:start()\n```\n\nUse `PaperWM:bindHotkeys(PaperWM.default_hotkeys)` for defaults.\n\nSet `PaperWM.window_gap` to the number of pixels to space between windows and\nthe top and bottom screen edges.\n\nOverwrite `PaperWM.window_filter` to ignore specific applications. For example:\n\n```\nPaperWM.window_filter = PaperWM.window_filter:setAppFilter(\"Finder\", false)\nPaperWM:start() -- restart for new window filter to take effect\n```\n\n# Limitations\n\nUnder System Preferences -> Mission Control, unselect \"Automatically\nrearrange Spaces based on most recent use\" and select \"Displays have separate\nSpaces\".\n\nMacOS does not allow a window to be moved fully off-screen. Windows that would\nbe tiled off-screen are placed in a margin on the left and right edge of the\nscreen. They are still visible and clickable.\n\nIt's difficult to detect when a window is dragged from one space or screen to\nanother. Use the move_window_N commands to move windows between spaces and\nscreens.\n\nArrange screens vertically to prevent windows from bleeding into other screens.\n\n\nDownload: [https://github.com/mogenson/PaperWM.spoon](https://github.com/mogenson/PaperWM.spoon)", + "items": [ + { + "def": "PaperWM:addWindow(add_window)", + "desc": "Adds a window to layout and tiles.", + "doc": "Adds a window to layout and tiles.\n\nParameters:\n * add_window - An hs.window\n\nReturns:\n * The hs.spaces space for added window or nil if window not added.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "594", + "name": "addWindow", + "notes": [], + "parameters": [ + " * add_window - An hs.window" + ], + "returns": [ + " * The hs.spaces space for added window or nil if window not added." + ], + "signature": "PaperWM:addWindow(add_window)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:barfWindow()", + "desc": "Removes current window from column and places it to the right", + "doc": "Removes current window from column and places it to the right\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "1026", + "name": "barfWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:barfWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.bindHotkeys(mapping)", + "desc": "Binds hotkeys for PaperWM", + "doc": "Binds hotkeys for PaperWM\n\nParameters:\n * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "275", + "name": "bindHotkeys", + "notes": [], + "parameters": [ + " * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9" + ], + "returns": [], + "signature": "PaperWM.bindHotkeys(mapping)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:centerWindow()", + "desc": "Moves current window to center of screen, without resizing.", + "doc": "Moves current window to center of screen, without resizing.\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "860", + "name": "centerWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:centerWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:cycleWindowSize(direction)", + "desc": "Resizes current window by cycling through width or height ratios.", + "doc": "Resizes current window by cycling through width or height ratios.\n\nParameters:\n * direction - One of Direction { WIDTH, HEIGHT }", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "907", + "name": "cycleWindowSize", + "notes": [], + "parameters": [ + " * direction - One of Direction { WIDTH, HEIGHT }" + ], + "returns": [], + "signature": "PaperWM:cycleWindowSize(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.default_hotkeys", + "desc": "Default hotkeys for moving / resizing windows", + "doc": "Default hotkeys for moving / resizing windows", + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "111", + "name": "default_hotkeys", + "signature": "PaperWM.default_hotkeys", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM:focusWindow(direction, focused_index)", + "desc": "Change focus to a nearby window", + "doc": "Change focus to a nearby window\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }\n * focused_index - The coordinates of the current window in the tiling layout\n\nReturns:\n * A boolean. True if a new window was focused. False if no nearby window\n was found in that direction.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "699", + "name": "focusWindow", + "notes": [], + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + " * focused_index - The coordinates of the current window in the tiling layout" + ], + "returns": [ + " * A boolean. True if a new window was focused. False if no nearby window", + " was found in that direction." + ], + "signature": "PaperWM:focusWindow(direction, focused_index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.logger", + "desc": "Logger object. Can be accessed to set default log level.", + "doc": "Logger object. Can be accessed to set default log level.", + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "165", + "name": "logger", + "signature": "PaperWM.logger", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM::moveWindow(window, frame)", + "desc": "Resizes a window without triggering a windowMoved event", + "doc": "Resizes a window without triggering a windowMoved event\n\nParameters:\n * window - An hs.window\n * frame - An hs.geometry.rect for the windows new frame size.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "1147", + "name": "moveWindow", + "notes": [], + "parameters": [ + " * window - An hs.window", + " * frame - An hs.geometry.rect for the windows new frame size." + ], + "returns": [], + "signature": "PaperWM::moveWindow(window, frame)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:moveWindowToSpace(index)", + "desc": "Moves the current window to a new Mission Control space", + "doc": "Moves the current window to a new Mission Control space\n\nParameters:\n * index - The space number", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "1096", + "name": "moveWindowToSpace", + "notes": [], + "parameters": [ + " * index - The space number" + ], + "returns": [], + "signature": "PaperWM:moveWindowToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:refreshWindows()", + "desc": "Searches for all windows that match window filter.", + "doc": "Searches for all windows that match window filter.\n\nParameters:\n * None\n\nReturns:\n * A boolean, true if the layout needs to be re-tiled, false if no change.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "563", + "name": "refreshWindows", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * A boolean, true if the layout needs to be re-tiled, false if no change." + ], + "signature": "PaperWM:refreshWindows()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "desc": "Remove window from tiling layout", + "doc": "Remove window from tiling layout\n\nParameters:\n * remove_window - A hs.window to remove from tiling layout\n * skip_new_window_focus - A boolean. True if a nearby window should not be\n focused after current window is removed.\n\nReturns:\n * The hs.spaces space for removed window.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "652", + "name": "remove_window", + "notes": [], + "parameters": [ + " * remove_window - A hs.window to remove from tiling layout", + " * skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed." + ], + "returns": [ + " * The hs.spaces space for removed window." + ], + "signature": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:setWindowFullWidth()", + "desc": "Resizes current window's width to width of screen, without adjusting height.", + "doc": "Resizes current window's width to width of screen, without adjusting height.\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "885", + "name": "setWindowFullWidth", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:setWindowFullWidth()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:slurpWindow()", + "desc": "Moves current window into column of windows to the left", + "doc": "Moves current window into column of windows to the left\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "961", + "name": "slurpWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:slurpWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:start()", + "desc": "Start automatic tiling of windows", + "doc": "Start automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "354", + "name": "start", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The PaperWM object" + ], + "signature": "PaperWM:start()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:stop()", + "desc": "Stop automatic tiling of windows", + "doc": "Stop automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "391", + "name": "stop", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The PaperWM object" + ], + "signature": "PaperWM:stop()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:swapWindows(direction)", + "desc": "Swaps window postions between current window and window in specified direction.", + "doc": "Swaps window postions between current window and window in specified direction.\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "749", + "name": "swapWindows", + "notes": [], + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }" + ], + "returns": [], + "signature": "PaperWM:swapWindows(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:switchToSpace(index)", + "desc": "Switch to a Mission Control space", + "doc": "Switch to a Mission Control space\n\nParameters:\n * index - The space number", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "1080", + "name": "switchToSpace", + "notes": [], + "parameters": [ + " * index - The space number" + ], + "returns": [], + "signature": "PaperWM:switchToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "desc": "Tile a column of windows", + "doc": "Tile a column of windows\n\nParameters:\n * windows - A list of hs.windows.\n * bounds - An hs.geometry.rect. The area for this column to fill.\n * h - The height for each window in column.\n * w - The width for each window in column.\n * id - A hs.window.id() for a specific window in column.\n * h4id - The height for a window matching id in column.\n\nNotes:\n * The h, w, id, and h4id parameters are optional. The height and width of\n all windows will be calculated and set to fill column bounds.\n * If bounds width is not specified, all windows in column will be resized\n to width of first window.\n\nReturns:\n * The width of the column", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "408", + "name": "tileColumn", + "notes": [ + " * The h, w, id, and h4id parameters are optional. The height and width of", + " all windows will be calculated and set to fill column bounds.", + " * If bounds width is not specified, all windows in column will be resized", + " to width of first window." + ], + "parameters": [ + " * windows - A list of hs.windows.", + " * bounds - An hs.geometry.rect. The area for this column to fill.", + " * h - The height for each window in column.", + " * w - The width for each window in column.", + " * id - A hs.window.id() for a specific window in column.", + " * h4id - The height for a window matching id in column." + ], + "returns": [ + " * The width of the column" + ], + "signature": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileSpace(space)", + "desc": "Tile all windows within a space", + "doc": "Tile all windows within a space\n\nParameters:\n * space - A hs.spaces space.", + "examples": [], + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "460", + "name": "tileSpace", + "notes": [], + "parameters": [ + " * space - A hs.spaces space." + ], + "returns": [], + "signature": "PaperWM:tileSpace(space)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.window_filter", + "desc": "Windows captured by this filter are automatically tiled and managed", + "doc": "Windows captured by this filter are automatically tiled and managed", + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "150", + "name": "window_filter", + "signature": "PaperWM.window_filter", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_gap", + "desc": "Number of pixels between tiled windows", + "doc": "Number of pixels between tiled windows", + "file": "Source/PaperWM.spoon//init.lua", + "lineno": "160", + "name": "window_gap", + "signature": "PaperWM.window_gap", + "stripped_doc": "", + "type": "Variable" + } + ], + "name": "PaperWM", + "stripped_doc": "\n# Usage\n\n`PaperWM:start()` will begin automatically tiling new and existing windows.\n`PaperWM:stop()` will release control over windows.\n`PaperWM::bindHotkeys()` will move / resize windows using keyboard shortcuts.\n\nHere is an example Hammerspoon config:\n\n```\nPaperWM = hs.loadSpoon(\"PaperWM\")\nPaperWM:bindHotkeys({\n -- switch to a new focused window in tiled grid\n focus_left = {{\"ctrl\", \"alt\", \"cmd\"}, \"left\"},\n focus_right = {{\"ctrl\", \"alt\", \"cmd\"}, \"right\"},\n focus_up = {{\"ctrl\", \"alt\", \"cmd\"}, \"up\"},\n focus_down = {{\"ctrl\", \"alt\", \"cmd\"}, \"down\"},\n\n -- move windows around in tiled grid\n swap_left = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"left\"},\n swap_right = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"right\"},\n swap_up = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"up\"},\n swap_down = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"down\"},\n\n -- position and resize focused window\n center_window = {{\"ctrl\", \"alt\", \"cmd\"}, \"c\"},\n full_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"f\"},\n cycle_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"r\"},\n cycle_height = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"r\"},\n\n -- move focused window into / out of a column\n slurp_in = {{\"ctrl\", \"alt\", \"cmd\"}, \"i\"},\n barf_out = {{\"ctrl\", \"alt\", \"cmd\"}, \"o\"},\n\n -- switch to a new Mission Control space\n switch_space_1 = {{\"ctrl\", \"alt\", \"cmd\"}, \"1\"},\n switch_space_2 = {{\"ctrl\", \"alt\", \"cmd\"}, \"2\"},\n switch_space_3 = {{\"ctrl\", \"alt\", \"cmd\"}, \"3\"},\n switch_space_4 = {{\"ctrl\", \"alt\", \"cmd\"}, \"4\"},\n switch_space_5 = {{\"ctrl\", \"alt\", \"cmd\"}, \"5\"},\n switch_space_6 = {{\"ctrl\", \"alt\", \"cmd\"}, \"6\"},\n switch_space_7 = {{\"ctrl\", \"alt\", \"cmd\"}, \"7\"},\n switch_space_8 = {{\"ctrl\", \"alt\", \"cmd\"}, \"8\"},\n switch_space_9 = {{\"ctrl\", \"alt\", \"cmd\"}, \"9\"},\n\n -- move focused window to a new space and tile\n move_window_1 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"1\"},\n move_window_2 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"2\"},\n move_window_3 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"3\"},\n move_window_4 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"4\"},\n move_window_5 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"5\"},\n move_window_6 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"6\"},\n move_window_7 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"7\"},\n move_window_8 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"8\"},\n move_window_9 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"9\"}\n})\nPaperWM:start()\n```\n\nUse `PaperWM:bindHotkeys(PaperWM.default_hotkeys)` for defaults.\n\nSet `PaperWM.window_gap` to the number of pixels to space between windows and\nthe top and bottom screen edges.\n\nOverwrite `PaperWM.window_filter` to ignore specific applications. For example:\n\n```\nPaperWM.window_filter = PaperWM.window_filter:setAppFilter(\"Finder\", false)\nPaperWM:start() -- restart for new window filter to take effect\n```\n\n# Limitations\n\nUnder System Preferences -> Mission Control, unselect \"Automatically\nrearrange Spaces based on most recent use\" and select \"Displays have separate\nSpaces\".\n\nMacOS does not allow a window to be moved fully off-screen. Windows that would\nbe tiled off-screen are placed in a margin on the left and right edge of the\nscreen. They are still visible and clickable.\n\nIt's difficult to detect when a window is dragged from one space or screen to\nanother. Use the move_window_N commands to move windows between spaces and\nscreens.\n\nArrange screens vertically to prevent windows from bleeding into other screens.\n\n\nDownload: [https://github.com/mogenson/PaperWM.spoon](https://github.com/mogenson/PaperWM.spoon)", + "submodules": [], + "type": "Module" + } +] \ No newline at end of file From 5fc96b056404a02e5b7965fc7d7d915c5bb4d796 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:31:56 +0000 Subject: [PATCH 42/55] Add binary package for PaperWM. --- Spoons/PaperWM.spoon.zip | Bin 0 -> 12983 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Spoons/PaperWM.spoon.zip diff --git a/Spoons/PaperWM.spoon.zip b/Spoons/PaperWM.spoon.zip new file mode 100644 index 0000000000000000000000000000000000000000..deefc4c8a70aa6b9f4b0f5daadd7391eb6ccd758 GIT binary patch literal 12983 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∨pqe1u4h)ne@-wzbWafQ`1hTKacs2fZsg`(p$j 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 Date: Wed, 7 Aug 2024 13:31:57 +0000 Subject: [PATCH 43/55] Update docs --- docs/PaperWM.html | 909 ++++++++++++++++++++++++++++++++++ docs/docs.json | 776 +++++++++++++++++++++++++++++ docs/docs_index.json | 137 +++++ docs/index.html | 5 + docs/templated_docs.json | 1018 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 2845 insertions(+) create mode 100644 docs/PaperWM.html diff --git a/docs/PaperWM.html b/docs/PaperWM.html new file mode 100644 index 00000000..c250194f --- /dev/null +++ b/docs/PaperWM.html @@ -0,0 +1,909 @@ + + + + Hammerspoon docs: PaperWM + + + + +
+

docs » PaperWM

+

A scrolling window manager. Inspired by PaperWM Gnome extension.

+

Usage

+

PaperWM:start() will begin automatically tiling new and existing windows. +PaperWM:stop() will release control over windows. +PaperWM::bindHotkeys() will move / resize windows using keyboard shortcuts.

+

Here is an example Hammerspoon config:

+ +
PaperWM = hs.loadSpoon("PaperWM")
+PaperWM:bindHotkeys({
+    -- switch to a new focused window in tiled grid
+    focus_left  = {{"ctrl", "alt", "cmd"}, "left"},
+    focus_right = {{"ctrl", "alt", "cmd"}, "right"},
+    focus_up    = {{"ctrl", "alt", "cmd"}, "up"},
+    focus_down  = {{"ctrl", "alt", "cmd"}, "down"},
+
+    -- move windows around in tiled grid
+    swap_left  = {{"ctrl", "alt", "cmd", "shift"}, "left"},
+    swap_right = {{"ctrl", "alt", "cmd", "shift"}, "right"},
+    swap_up    = {{"ctrl", "alt", "cmd", "shift"}, "up"},
+    swap_down  = {{"ctrl", "alt", "cmd", "shift"}, "down"},
+
+    -- position and resize focused window
+    center_window = {{"ctrl", "alt", "cmd"}, "c"},
+    full_width    = {{"ctrl", "alt", "cmd"}, "f"},
+    cycle_width   = {{"ctrl", "alt", "cmd"}, "r"},
+    cycle_height  = {{"ctrl", "alt", "cmd", "shift"}, "r"},
+
+    -- move focused window into / out of a column
+    slurp_in = {{"ctrl", "alt", "cmd"}, "i"},
+    barf_out = {{"ctrl", "alt", "cmd"}, "o"},
+
+    -- switch to a new Mission Control space
+    switch_space_1 = {{"ctrl", "alt", "cmd"}, "1"},
+    switch_space_2 = {{"ctrl", "alt", "cmd"}, "2"},
+    switch_space_3 = {{"ctrl", "alt", "cmd"}, "3"},
+    switch_space_4 = {{"ctrl", "alt", "cmd"}, "4"},
+    switch_space_5 = {{"ctrl", "alt", "cmd"}, "5"},
+    switch_space_6 = {{"ctrl", "alt", "cmd"}, "6"},
+    switch_space_7 = {{"ctrl", "alt", "cmd"}, "7"},
+    switch_space_8 = {{"ctrl", "alt", "cmd"}, "8"},
+    switch_space_9 = {{"ctrl", "alt", "cmd"}, "9"},
+
+    -- move focused window to a new space and tile
+    move_window_1 = {{"ctrl", "alt", "cmd", "shift"}, "1"},
+    move_window_2 = {{"ctrl", "alt", "cmd", "shift"}, "2"},
+    move_window_3 = {{"ctrl", "alt", "cmd", "shift"}, "3"},
+    move_window_4 = {{"ctrl", "alt", "cmd", "shift"}, "4"},
+    move_window_5 = {{"ctrl", "alt", "cmd", "shift"}, "5"},
+    move_window_6 = {{"ctrl", "alt", "cmd", "shift"}, "6"},
+    move_window_7 = {{"ctrl", "alt", "cmd", "shift"}, "7"},
+    move_window_8 = {{"ctrl", "alt", "cmd", "shift"}, "8"},
+    move_window_9 = {{"ctrl", "alt", "cmd", "shift"}, "9"}
+})
+PaperWM:start()
+
+

Use PaperWM:bindHotkeys(PaperWM.default_hotkeys) for defaults.

+

Set PaperWM.window_gap to the number of pixels to space between windows and +the top and bottom screen edges.

+

Overwrite PaperWM.window_filter to ignore specific applications. For example:

+ +
PaperWM.window_filter = PaperWM.window_filter:setAppFilter("Finder", false)
+PaperWM:start() -- restart for new window filter to take effect
+
+

Limitations

+

Under System Preferences -> Mission Control, unselect "Automatically +rearrange Spaces based on most recent use" and select "Displays have separate +Spaces".

+

MacOS does not allow a window to be moved fully off-screen. Windows that would +be tiled off-screen are placed in a margin on the left and right edge of the +screen. They are still visible and clickable.

+

It's difficult to detect when a window is dragged from one space or screen to +another. Use the move_window_N commands to move windows between spaces and +screens.

+

Arrange screens vertically to prevent windows from bleeding into other screens.

+

Download: https://github.com/mogenson/PaperWM.spoon

+ +
+

API Overview

+ +

API Documentation

+

Variables

+
+ +
default_hotkeys
+ + + + + + + + + + + + + + + + + +
SignaturePaperWM.default_hotkeys
TypeVariable
Description

Default hotkeys for moving / resizing windows

+
SourceSource/PaperWM.spoon/init.lua line 111
+
+
+ +
logger
+ + + + + + + + + + + + + + + + + +
SignaturePaperWM.logger
TypeVariable
Description

Logger object. Can be accessed to set default log level.

+
SourceSource/PaperWM.spoon/init.lua line 165
+
+
+ +
window_filter
+ + + + + + + + + + + + + + + + + +
SignaturePaperWM.window_filter
TypeVariable
Description

Windows captured by this filter are automatically tiled and managed

+
SourceSource/PaperWM.spoon/init.lua line 150
+
+
+ +
window_gap
+ + + + + + + + + + + + + + + + + +
SignaturePaperWM.window_gap
TypeVariable
Description

Number of pixels between tiled windows

+
SourceSource/PaperWM.spoon/init.lua line 160
+
+

Methods

+
+ +
addWindow
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:addWindow(add_window)
TypeMethod
Description

Adds a window to layout and tiles.

+
Parameters
    +
  • add_window - An hs.window
  • +
+
Returns
    +
  • The hs.spaces space for added window or nil if window not added.
  • +
+
SourceSource/PaperWM.spoon/init.lua line 594
+
+
+ +
barfWindow
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:barfWindow()
TypeMethod
Description

Removes current window from column and places it to the right

+
Parameters
    +
  • None
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 1026
+
+
+ +
bindHotkeys
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM.bindHotkeys(mapping)
TypeMethod
Description

Binds hotkeys for PaperWM

+
Parameters
    +
  • mapping - A table containing hotkey modifer/key details for the following items:
      +
    • stop_events - Stop automatic tiling
    • +
    • focus_left - Focus window to left of current window
    • +
    • focus_right - Focus window to right of current window
    • +
    • focus_up - Focus window to up of current window
    • +
    • focus_down - Focus window to down of current window
    • +
    • swap_left - Swap positions of window to the left and current window
    • +
    • swap_right - Swap positions of window to the right and current window
    • +
    • swap_up - Swap positions of window above and current window
    • +
    • swap_down - Swap positions of window below and current window
    • +
    • center_window - Move current window to center of screen
    • +
    • full_width - Resize width of current window to width of screen
    • +
    • cycle_width - Toggle through preset window widths
    • +
    • cycle_height - Toggle through preset window heights
    • +
    • slurp_in - Move current window into column to the left
    • +
    • barf_out - Remove current window from column and place to the right
    • +
    • switch_space_1 - Switch to Mission Control space 1
    • +
    • switch_space_2 - Switch to Mission Control space 2
    • +
    • switch_space_3 - Switch to Mission Control space 3
    • +
    • switch_space_4 - Switch to Mission Control space 4
    • +
    • switch_space_5 - Switch to Mission Control space 5
    • +
    • switch_space_6 - Switch to Mission Control space 6
    • +
    • switch_space_7 - Switch to Mission Control space 7
    • +
    • switch_space_8 - Switch to Mission Control space 8
    • +
    • switch_space_9 - Switch to Mission Control space 9
    • +
    • move_window_1 - Move current window to Mission Control space 1
    • +
    • move_window_2 - Move current window to Mission Control space 2
    • +
    • move_window_3 - Move current window to Mission Control space 3
    • +
    • move_window_4 - Move current window to Mission Control space 4
    • +
    • move_window_5 - Move current window to Mission Control space 5
    • +
    • move_window_6 - Move current window to Mission Control space 6
    • +
    • move_window_7 - Move current window to Mission Control space 7
    • +
    • move_window_8 - Move current window to Mission Control space 8
    • +
    • move_window_9 - Move current window to Mission Control space 9
    • +
    +
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 275
+
+
+ +
centerWindow
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:centerWindow()
TypeMethod
Description

Moves current window to center of screen, without resizing.

+
Parameters
    +
  • None
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 860
+
+
+ +
cycleWindowSize
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:cycleWindowSize(direction)
TypeMethod
Description

Resizes current window by cycling through width or height ratios.

+
Parameters
    +
  • direction - One of Direction { WIDTH, HEIGHT }
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 907
+
+
+ +
focusWindow
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:focusWindow(direction, focused_index)
TypeMethod
Description

Change focus to a nearby window

+
Parameters
    +
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • +
  • focused_index - The coordinates of the current window in the tiling layout
  • +
+
Returns
    +
  • A boolean. True if a new window was focused. False if no nearby window +was found in that direction.
  • +
+
SourceSource/PaperWM.spoon/init.lua line 699
+
+
+ +
moveWindow
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM::moveWindow(window, frame)
TypeMethod
Description

Resizes a window without triggering a windowMoved event

+
Parameters
    +
  • window - An hs.window
  • +
  • frame - An hs.geometry.rect for the windows new frame size.
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 1147
+
+
+ +
moveWindowToSpace
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:moveWindowToSpace(index)
TypeMethod
Description

Moves the current window to a new Mission Control space

+
Parameters
    +
  • index - The space number
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 1096
+
+
+ +
refreshWindows
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:refreshWindows()
TypeMethod
Description

Searches for all windows that match window filter.

+
Parameters
    +
  • None
  • +
+
Returns
    +
  • A boolean, true if the layout needs to be re-tiled, false if no change.
  • +
+
SourceSource/PaperWM.spoon/init.lua line 563
+
+
+ +
remove_window
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:remove_window(remove_window, skip_new_window_focus)
TypeMethod
Description

Remove window from tiling layout

+
Parameters
    +
  • remove_window - A hs.window to remove from tiling layout
  • +
  • skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed.
  • +
+
Returns
    +
  • The hs.spaces space for removed window.
  • +
+
SourceSource/PaperWM.spoon/init.lua line 652
+
+
+ +
setWindowFullWidth
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:setWindowFullWidth()
TypeMethod
Description

Resizes current window's width to width of screen, without adjusting height.

+
Parameters
    +
  • None
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 885
+
+
+ +
slurpWindow
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:slurpWindow()
TypeMethod
Description

Moves current window into column of windows to the left

+
Parameters
    +
  • None
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 961
+
+
+ +
start
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:start()
TypeMethod
Description

Start automatic tiling of windows

+
Parameters
    +
  • None
  • +
+
Returns
    +
  • The PaperWM object
  • +
+
SourceSource/PaperWM.spoon/init.lua line 354
+
+
+ +
stop
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:stop()
TypeMethod
Description

Stop automatic tiling of windows

+
Parameters
    +
  • None
  • +
+
Returns
    +
  • The PaperWM object
  • +
+
SourceSource/PaperWM.spoon/init.lua line 391
+
+
+ +
swapWindows
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:swapWindows(direction)
TypeMethod
Description

Swaps window postions between current window and window in specified direction.

+
Parameters
    +
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 749
+
+
+ +
switchToSpace
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:switchToSpace(index)
TypeMethod
Description

Switch to a Mission Control space

+
Parameters
    +
  • index - The space number
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 1080
+
+
+ +
tileColumn
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:tileColumn(windows, bounds, h, w, id, h4id)
TypeMethod
Description

Tile a column of windows

+
Parameters
    +
  • windows - A list of hs.windows.
  • +
  • bounds - An hs.geometry.rect. The area for this column to fill.
  • +
  • h - The height for each window in column.
  • +
  • w - The width for each window in column.
  • +
  • id - A hs.window.id() for a specific window in column.
  • +
  • h4id - The height for a window matching id in column.
  • +
+
Returns
    +
  • The width of the column
  • +
+
Notes
    +
  • The h, w, id, and h4id parameters are optional. The height and width of +all windows will be calculated and set to fill column bounds.
  • +
  • If bounds width is not specified, all windows in column will be resized +to width of first window.
  • +
+
SourceSource/PaperWM.spoon/init.lua line 408
+
+
+ +
tileSpace
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignaturePaperWM:tileSpace(space)
TypeMethod
Description

Tile all windows within a space

+
Parameters
    +
  • space - A hs.spaces space.
  • +
+
Returns
SourceSource/PaperWM.spoon/init.lua line 460
+
+ + \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index 0e487cf5..97883891 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -10389,6 +10389,782 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "PaperWM:addWindow(add_window)", + "desc": "Adds a window to layout and tiles.", + "doc": "Adds a window to layout and tiles.\n\nParameters:\n * add_window - An hs.window\n\nReturns:\n * The hs.spaces space for added window or nil if window not added.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "594", + "name": "addWindow", + "notes": [], + "parameters": [ + " * add_window - An hs.window" + ], + "returns": [ + " * The hs.spaces space for added window or nil if window not added." + ], + "signature": "PaperWM:addWindow(add_window)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:barfWindow()", + "desc": "Removes current window from column and places it to the right", + "doc": "Removes current window from column and places it to the right\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1026", + "name": "barfWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:barfWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.bindHotkeys(mapping)", + "desc": "Binds hotkeys for PaperWM", + "doc": "Binds hotkeys for PaperWM\n\nParameters:\n * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "275", + "name": "bindHotkeys", + "notes": [], + "parameters": [ + " * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9" + ], + "returns": [], + "signature": "PaperWM.bindHotkeys(mapping)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:centerWindow()", + "desc": "Moves current window to center of screen, without resizing.", + "doc": "Moves current window to center of screen, without resizing.\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "860", + "name": "centerWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:centerWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:cycleWindowSize(direction)", + "desc": "Resizes current window by cycling through width or height ratios.", + "doc": "Resizes current window by cycling through width or height ratios.\n\nParameters:\n * direction - One of Direction { WIDTH, HEIGHT }", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "907", + "name": "cycleWindowSize", + "notes": [], + "parameters": [ + " * direction - One of Direction { WIDTH, HEIGHT }" + ], + "returns": [], + "signature": "PaperWM:cycleWindowSize(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:focusWindow(direction, focused_index)", + "desc": "Change focus to a nearby window", + "doc": "Change focus to a nearby window\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }\n * focused_index - The coordinates of the current window in the tiling layout\n\nReturns:\n * A boolean. True if a new window was focused. False if no nearby window\n was found in that direction.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "699", + "name": "focusWindow", + "notes": [], + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + " * focused_index - The coordinates of the current window in the tiling layout" + ], + "returns": [ + " * A boolean. True if a new window was focused. False if no nearby window", + " was found in that direction." + ], + "signature": "PaperWM:focusWindow(direction, focused_index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM::moveWindow(window, frame)", + "desc": "Resizes a window without triggering a windowMoved event", + "doc": "Resizes a window without triggering a windowMoved event\n\nParameters:\n * window - An hs.window\n * frame - An hs.geometry.rect for the windows new frame size.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1147", + "name": "moveWindow", + "notes": [], + "parameters": [ + " * window - An hs.window", + " * frame - An hs.geometry.rect for the windows new frame size." + ], + "returns": [], + "signature": "PaperWM::moveWindow(window, frame)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:moveWindowToSpace(index)", + "desc": "Moves the current window to a new Mission Control space", + "doc": "Moves the current window to a new Mission Control space\n\nParameters:\n * index - The space number", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1096", + "name": "moveWindowToSpace", + "notes": [], + "parameters": [ + " * index - The space number" + ], + "returns": [], + "signature": "PaperWM:moveWindowToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:refreshWindows()", + "desc": "Searches for all windows that match window filter.", + "doc": "Searches for all windows that match window filter.\n\nParameters:\n * None\n\nReturns:\n * A boolean, true if the layout needs to be re-tiled, false if no change.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "563", + "name": "refreshWindows", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * A boolean, true if the layout needs to be re-tiled, false if no change." + ], + "signature": "PaperWM:refreshWindows()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "desc": "Remove window from tiling layout", + "doc": "Remove window from tiling layout\n\nParameters:\n * remove_window - A hs.window to remove from tiling layout\n * skip_new_window_focus - A boolean. True if a nearby window should not be\n focused after current window is removed.\n\nReturns:\n * The hs.spaces space for removed window.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "652", + "name": "remove_window", + "notes": [], + "parameters": [ + " * remove_window - A hs.window to remove from tiling layout", + " * skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed." + ], + "returns": [ + " * The hs.spaces space for removed window." + ], + "signature": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:setWindowFullWidth()", + "desc": "Resizes current window's width to width of screen, without adjusting height.", + "doc": "Resizes current window's width to width of screen, without adjusting height.\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "885", + "name": "setWindowFullWidth", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:setWindowFullWidth()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:slurpWindow()", + "desc": "Moves current window into column of windows to the left", + "doc": "Moves current window into column of windows to the left\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "961", + "name": "slurpWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:slurpWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:start()", + "desc": "Start automatic tiling of windows", + "doc": "Start automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "354", + "name": "start", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The PaperWM object" + ], + "signature": "PaperWM:start()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:stop()", + "desc": "Stop automatic tiling of windows", + "doc": "Stop automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "391", + "name": "stop", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The PaperWM object" + ], + "signature": "PaperWM:stop()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:swapWindows(direction)", + "desc": "Swaps window postions between current window and window in specified direction.", + "doc": "Swaps window postions between current window and window in specified direction.\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "749", + "name": "swapWindows", + "notes": [], + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }" + ], + "returns": [], + "signature": "PaperWM:swapWindows(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:switchToSpace(index)", + "desc": "Switch to a Mission Control space", + "doc": "Switch to a Mission Control space\n\nParameters:\n * index - The space number", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1080", + "name": "switchToSpace", + "notes": [], + "parameters": [ + " * index - The space number" + ], + "returns": [], + "signature": "PaperWM:switchToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "desc": "Tile a column of windows", + "doc": "Tile a column of windows\n\nParameters:\n * windows - A list of hs.windows.\n * bounds - An hs.geometry.rect. The area for this column to fill.\n * h - The height for each window in column.\n * w - The width for each window in column.\n * id - A hs.window.id() for a specific window in column.\n * h4id - The height for a window matching id in column.\n\nNotes:\n * The h, w, id, and h4id parameters are optional. The height and width of\n all windows will be calculated and set to fill column bounds.\n * If bounds width is not specified, all windows in column will be resized\n to width of first window.\n\nReturns:\n * The width of the column", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "408", + "name": "tileColumn", + "notes": [ + " * The h, w, id, and h4id parameters are optional. The height and width of", + " all windows will be calculated and set to fill column bounds.", + " * If bounds width is not specified, all windows in column will be resized", + " to width of first window." + ], + "parameters": [ + " * windows - A list of hs.windows.", + " * bounds - An hs.geometry.rect. The area for this column to fill.", + " * h - The height for each window in column.", + " * w - The width for each window in column.", + " * id - A hs.window.id() for a specific window in column.", + " * h4id - The height for a window matching id in column." + ], + "returns": [ + " * The width of the column" + ], + "signature": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileSpace(space)", + "desc": "Tile all windows within a space", + "doc": "Tile all windows within a space\n\nParameters:\n * space - A hs.spaces space.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "460", + "name": "tileSpace", + "notes": [], + "parameters": [ + " * space - A hs.spaces space." + ], + "returns": [], + "signature": "PaperWM:tileSpace(space)", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [ + { + "def": "PaperWM.default_hotkeys", + "desc": "Default hotkeys for moving / resizing windows", + "doc": "Default hotkeys for moving / resizing windows", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "111", + "name": "default_hotkeys", + "signature": "PaperWM.default_hotkeys", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.logger", + "desc": "Logger object. Can be accessed to set default log level.", + "doc": "Logger object. Can be accessed to set default log level.", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "165", + "name": "logger", + "signature": "PaperWM.logger", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_filter", + "desc": "Windows captured by this filter are automatically tiled and managed", + "doc": "Windows captured by this filter are automatically tiled and managed", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "150", + "name": "window_filter", + "signature": "PaperWM.window_filter", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_gap", + "desc": "Number of pixels between tiled windows", + "doc": "Number of pixels between tiled windows", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "160", + "name": "window_gap", + "signature": "PaperWM.window_gap", + "stripped_doc": "", + "type": "Variable" + } + ], + "desc": "A scrolling window manager. Inspired by PaperWM Gnome extension.", + "doc": "A scrolling window manager. Inspired by PaperWM Gnome extension.\n\n# Usage\n\n`PaperWM:start()` will begin automatically tiling new and existing windows.\n`PaperWM:stop()` will release control over windows.\n`PaperWM::bindHotkeys()` will move / resize windows using keyboard shortcuts.\n\nHere is an example Hammerspoon config:\n\n```\nPaperWM = hs.loadSpoon(\"PaperWM\")\nPaperWM:bindHotkeys({\n -- switch to a new focused window in tiled grid\n focus_left = {{\"ctrl\", \"alt\", \"cmd\"}, \"left\"},\n focus_right = {{\"ctrl\", \"alt\", \"cmd\"}, \"right\"},\n focus_up = {{\"ctrl\", \"alt\", \"cmd\"}, \"up\"},\n focus_down = {{\"ctrl\", \"alt\", \"cmd\"}, \"down\"},\n\n -- move windows around in tiled grid\n swap_left = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"left\"},\n swap_right = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"right\"},\n swap_up = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"up\"},\n swap_down = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"down\"},\n\n -- position and resize focused window\n center_window = {{\"ctrl\", \"alt\", \"cmd\"}, \"c\"},\n full_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"f\"},\n cycle_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"r\"},\n cycle_height = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"r\"},\n\n -- move focused window into / out of a column\n slurp_in = {{\"ctrl\", \"alt\", \"cmd\"}, \"i\"},\n barf_out = {{\"ctrl\", \"alt\", \"cmd\"}, \"o\"},\n\n -- switch to a new Mission Control space\n switch_space_1 = {{\"ctrl\", \"alt\", \"cmd\"}, \"1\"},\n switch_space_2 = {{\"ctrl\", \"alt\", \"cmd\"}, \"2\"},\n switch_space_3 = {{\"ctrl\", \"alt\", \"cmd\"}, \"3\"},\n switch_space_4 = {{\"ctrl\", \"alt\", \"cmd\"}, \"4\"},\n switch_space_5 = {{\"ctrl\", \"alt\", \"cmd\"}, \"5\"},\n switch_space_6 = {{\"ctrl\", \"alt\", \"cmd\"}, \"6\"},\n switch_space_7 = {{\"ctrl\", \"alt\", \"cmd\"}, \"7\"},\n switch_space_8 = {{\"ctrl\", \"alt\", \"cmd\"}, \"8\"},\n switch_space_9 = {{\"ctrl\", \"alt\", \"cmd\"}, \"9\"},\n\n -- move focused window to a new space and tile\n move_window_1 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"1\"},\n move_window_2 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"2\"},\n move_window_3 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"3\"},\n move_window_4 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"4\"},\n move_window_5 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"5\"},\n move_window_6 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"6\"},\n move_window_7 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"7\"},\n move_window_8 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"8\"},\n move_window_9 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"9\"}\n})\nPaperWM:start()\n```\n\nUse `PaperWM:bindHotkeys(PaperWM.default_hotkeys)` for defaults.\n\nSet `PaperWM.window_gap` to the number of pixels to space between windows and\nthe top and bottom screen edges.\n\nOverwrite `PaperWM.window_filter` to ignore specific applications. For example:\n\n```\nPaperWM.window_filter = PaperWM.window_filter:setAppFilter(\"Finder\", false)\nPaperWM:start() -- restart for new window filter to take effect\n```\n\n# Limitations\n\nUnder System Preferences -> Mission Control, unselect \"Automatically\nrearrange Spaces based on most recent use\" and select \"Displays have separate\nSpaces\".\n\nMacOS does not allow a window to be moved fully off-screen. Windows that would\nbe tiled off-screen are placed in a margin on the left and right edge of the\nscreen. They are still visible and clickable.\n\nIt's difficult to detect when a window is dragged from one space or screen to\nanother. Use the move_window_N commands to move windows between spaces and\nscreens.\n\nArrange screens vertically to prevent windows from bleeding into other screens.\n\n\nDownload: [https://github.com/mogenson/PaperWM.spoon](https://github.com/mogenson/PaperWM.spoon)", + "items": [ + { + "def": "PaperWM:addWindow(add_window)", + "desc": "Adds a window to layout and tiles.", + "doc": "Adds a window to layout and tiles.\n\nParameters:\n * add_window - An hs.window\n\nReturns:\n * The hs.spaces space for added window or nil if window not added.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "594", + "name": "addWindow", + "notes": [], + "parameters": [ + " * add_window - An hs.window" + ], + "returns": [ + " * The hs.spaces space for added window or nil if window not added." + ], + "signature": "PaperWM:addWindow(add_window)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:barfWindow()", + "desc": "Removes current window from column and places it to the right", + "doc": "Removes current window from column and places it to the right\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1026", + "name": "barfWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:barfWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.bindHotkeys(mapping)", + "desc": "Binds hotkeys for PaperWM", + "doc": "Binds hotkeys for PaperWM\n\nParameters:\n * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "275", + "name": "bindHotkeys", + "notes": [], + "parameters": [ + " * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9" + ], + "returns": [], + "signature": "PaperWM.bindHotkeys(mapping)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:centerWindow()", + "desc": "Moves current window to center of screen, without resizing.", + "doc": "Moves current window to center of screen, without resizing.\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "860", + "name": "centerWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:centerWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:cycleWindowSize(direction)", + "desc": "Resizes current window by cycling through width or height ratios.", + "doc": "Resizes current window by cycling through width or height ratios.\n\nParameters:\n * direction - One of Direction { WIDTH, HEIGHT }", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "907", + "name": "cycleWindowSize", + "notes": [], + "parameters": [ + " * direction - One of Direction { WIDTH, HEIGHT }" + ], + "returns": [], + "signature": "PaperWM:cycleWindowSize(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.default_hotkeys", + "desc": "Default hotkeys for moving / resizing windows", + "doc": "Default hotkeys for moving / resizing windows", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "111", + "name": "default_hotkeys", + "signature": "PaperWM.default_hotkeys", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM:focusWindow(direction, focused_index)", + "desc": "Change focus to a nearby window", + "doc": "Change focus to a nearby window\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }\n * focused_index - The coordinates of the current window in the tiling layout\n\nReturns:\n * A boolean. True if a new window was focused. False if no nearby window\n was found in that direction.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "699", + "name": "focusWindow", + "notes": [], + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + " * focused_index - The coordinates of the current window in the tiling layout" + ], + "returns": [ + " * A boolean. True if a new window was focused. False if no nearby window", + " was found in that direction." + ], + "signature": "PaperWM:focusWindow(direction, focused_index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.logger", + "desc": "Logger object. Can be accessed to set default log level.", + "doc": "Logger object. Can be accessed to set default log level.", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "165", + "name": "logger", + "signature": "PaperWM.logger", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM::moveWindow(window, frame)", + "desc": "Resizes a window without triggering a windowMoved event", + "doc": "Resizes a window without triggering a windowMoved event\n\nParameters:\n * window - An hs.window\n * frame - An hs.geometry.rect for the windows new frame size.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1147", + "name": "moveWindow", + "notes": [], + "parameters": [ + " * window - An hs.window", + " * frame - An hs.geometry.rect for the windows new frame size." + ], + "returns": [], + "signature": "PaperWM::moveWindow(window, frame)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:moveWindowToSpace(index)", + "desc": "Moves the current window to a new Mission Control space", + "doc": "Moves the current window to a new Mission Control space\n\nParameters:\n * index - The space number", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1096", + "name": "moveWindowToSpace", + "notes": [], + "parameters": [ + " * index - The space number" + ], + "returns": [], + "signature": "PaperWM:moveWindowToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:refreshWindows()", + "desc": "Searches for all windows that match window filter.", + "doc": "Searches for all windows that match window filter.\n\nParameters:\n * None\n\nReturns:\n * A boolean, true if the layout needs to be re-tiled, false if no change.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "563", + "name": "refreshWindows", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * A boolean, true if the layout needs to be re-tiled, false if no change." + ], + "signature": "PaperWM:refreshWindows()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "desc": "Remove window from tiling layout", + "doc": "Remove window from tiling layout\n\nParameters:\n * remove_window - A hs.window to remove from tiling layout\n * skip_new_window_focus - A boolean. True if a nearby window should not be\n focused after current window is removed.\n\nReturns:\n * The hs.spaces space for removed window.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "652", + "name": "remove_window", + "notes": [], + "parameters": [ + " * remove_window - A hs.window to remove from tiling layout", + " * skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed." + ], + "returns": [ + " * The hs.spaces space for removed window." + ], + "signature": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:setWindowFullWidth()", + "desc": "Resizes current window's width to width of screen, without adjusting height.", + "doc": "Resizes current window's width to width of screen, without adjusting height.\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "885", + "name": "setWindowFullWidth", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:setWindowFullWidth()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:slurpWindow()", + "desc": "Moves current window into column of windows to the left", + "doc": "Moves current window into column of windows to the left\n\nParameters:\n * None", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "961", + "name": "slurpWindow", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "PaperWM:slurpWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:start()", + "desc": "Start automatic tiling of windows", + "doc": "Start automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "354", + "name": "start", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The PaperWM object" + ], + "signature": "PaperWM:start()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:stop()", + "desc": "Stop automatic tiling of windows", + "doc": "Stop automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "391", + "name": "stop", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The PaperWM object" + ], + "signature": "PaperWM:stop()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:swapWindows(direction)", + "desc": "Swaps window postions between current window and window in specified direction.", + "doc": "Swaps window postions between current window and window in specified direction.\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "749", + "name": "swapWindows", + "notes": [], + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }" + ], + "returns": [], + "signature": "PaperWM:swapWindows(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:switchToSpace(index)", + "desc": "Switch to a Mission Control space", + "doc": "Switch to a Mission Control space\n\nParameters:\n * index - The space number", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1080", + "name": "switchToSpace", + "notes": [], + "parameters": [ + " * index - The space number" + ], + "returns": [], + "signature": "PaperWM:switchToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "desc": "Tile a column of windows", + "doc": "Tile a column of windows\n\nParameters:\n * windows - A list of hs.windows.\n * bounds - An hs.geometry.rect. The area for this column to fill.\n * h - The height for each window in column.\n * w - The width for each window in column.\n * id - A hs.window.id() for a specific window in column.\n * h4id - The height for a window matching id in column.\n\nNotes:\n * The h, w, id, and h4id parameters are optional. The height and width of\n all windows will be calculated and set to fill column bounds.\n * If bounds width is not specified, all windows in column will be resized\n to width of first window.\n\nReturns:\n * The width of the column", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "408", + "name": "tileColumn", + "notes": [ + " * The h, w, id, and h4id parameters are optional. The height and width of", + " all windows will be calculated and set to fill column bounds.", + " * If bounds width is not specified, all windows in column will be resized", + " to width of first window." + ], + "parameters": [ + " * windows - A list of hs.windows.", + " * bounds - An hs.geometry.rect. The area for this column to fill.", + " * h - The height for each window in column.", + " * w - The width for each window in column.", + " * id - A hs.window.id() for a specific window in column.", + " * h4id - The height for a window matching id in column." + ], + "returns": [ + " * The width of the column" + ], + "signature": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileSpace(space)", + "desc": "Tile all windows within a space", + "doc": "Tile all windows within a space\n\nParameters:\n * space - A hs.spaces space.", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "460", + "name": "tileSpace", + "notes": [], + "parameters": [ + " * space - A hs.spaces space." + ], + "returns": [], + "signature": "PaperWM:tileSpace(space)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.window_filter", + "desc": "Windows captured by this filter are automatically tiled and managed", + "doc": "Windows captured by this filter are automatically tiled and managed", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "150", + "name": "window_filter", + "signature": "PaperWM.window_filter", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_gap", + "desc": "Number of pixels between tiled windows", + "doc": "Number of pixels between tiled windows", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "160", + "name": "window_gap", + "signature": "PaperWM.window_gap", + "stripped_doc": "", + "type": "Variable" + } + ], + "name": "PaperWM", + "stripped_doc": "\n# Usage\n\n`PaperWM:start()` will begin automatically tiling new and existing windows.\n`PaperWM:stop()` will release control over windows.\n`PaperWM::bindHotkeys()` will move / resize windows using keyboard shortcuts.\n\nHere is an example Hammerspoon config:\n\n```\nPaperWM = hs.loadSpoon(\"PaperWM\")\nPaperWM:bindHotkeys({\n -- switch to a new focused window in tiled grid\n focus_left = {{\"ctrl\", \"alt\", \"cmd\"}, \"left\"},\n focus_right = {{\"ctrl\", \"alt\", \"cmd\"}, \"right\"},\n focus_up = {{\"ctrl\", \"alt\", \"cmd\"}, \"up\"},\n focus_down = {{\"ctrl\", \"alt\", \"cmd\"}, \"down\"},\n\n -- move windows around in tiled grid\n swap_left = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"left\"},\n swap_right = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"right\"},\n swap_up = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"up\"},\n swap_down = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"down\"},\n\n -- position and resize focused window\n center_window = {{\"ctrl\", \"alt\", \"cmd\"}, \"c\"},\n full_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"f\"},\n cycle_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"r\"},\n cycle_height = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"r\"},\n\n -- move focused window into / out of a column\n slurp_in = {{\"ctrl\", \"alt\", \"cmd\"}, \"i\"},\n barf_out = {{\"ctrl\", \"alt\", \"cmd\"}, \"o\"},\n\n -- switch to a new Mission Control space\n switch_space_1 = {{\"ctrl\", \"alt\", \"cmd\"}, \"1\"},\n switch_space_2 = {{\"ctrl\", \"alt\", \"cmd\"}, \"2\"},\n switch_space_3 = {{\"ctrl\", \"alt\", \"cmd\"}, \"3\"},\n switch_space_4 = {{\"ctrl\", \"alt\", \"cmd\"}, \"4\"},\n switch_space_5 = {{\"ctrl\", \"alt\", \"cmd\"}, \"5\"},\n switch_space_6 = {{\"ctrl\", \"alt\", \"cmd\"}, \"6\"},\n switch_space_7 = {{\"ctrl\", \"alt\", \"cmd\"}, \"7\"},\n switch_space_8 = {{\"ctrl\", \"alt\", \"cmd\"}, \"8\"},\n switch_space_9 = {{\"ctrl\", \"alt\", \"cmd\"}, \"9\"},\n\n -- move focused window to a new space and tile\n move_window_1 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"1\"},\n move_window_2 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"2\"},\n move_window_3 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"3\"},\n move_window_4 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"4\"},\n move_window_5 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"5\"},\n move_window_6 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"6\"},\n move_window_7 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"7\"},\n move_window_8 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"8\"},\n move_window_9 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"9\"}\n})\nPaperWM:start()\n```\n\nUse `PaperWM:bindHotkeys(PaperWM.default_hotkeys)` for defaults.\n\nSet `PaperWM.window_gap` to the number of pixels to space between windows and\nthe top and bottom screen edges.\n\nOverwrite `PaperWM.window_filter` to ignore specific applications. For example:\n\n```\nPaperWM.window_filter = PaperWM.window_filter:setAppFilter(\"Finder\", false)\nPaperWM:start() -- restart for new window filter to take effect\n```\n\n# Limitations\n\nUnder System Preferences -> Mission Control, unselect \"Automatically\nrearrange Spaces based on most recent use\" and select \"Displays have separate\nSpaces\".\n\nMacOS does not allow a window to be moved fully off-screen. Windows that would\nbe tiled off-screen are placed in a margin on the left and right edge of the\nscreen. They are still visible and clickable.\n\nIt's difficult to detect when a window is dragged from one space or screen to\nanother. Use the move_window_N commands to move windows between spaces and\nscreens.\n\nArrange screens vertically to prevent windows from bleeding into other screens.\n\n\nDownload: [https://github.com/mogenson/PaperWM.spoon](https://github.com/mogenson/PaperWM.spoon)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], diff --git a/docs/docs_index.json b/docs/docs_index.json index c84269cf..63d51dc1 100644 --- a/docs/docs_index.json +++ b/docs/docs_index.json @@ -1933,6 +1933,143 @@ "name": "updateEventSubscriptions", "type": "Method" }, + { + "desc": "A scrolling window manager. Inspired by PaperWM Gnome extension.", + "name": "PaperWM", + "type": "Module" + }, + { + "desc": "Default hotkeys for moving / resizing windows", + "module": "PaperWM", + "name": "default_hotkeys", + "type": "Variable" + }, + { + "desc": "Logger object. Can be accessed to set default log level.", + "module": "PaperWM", + "name": "logger", + "type": "Variable" + }, + { + "desc": "Windows captured by this filter are automatically tiled and managed", + "module": "PaperWM", + "name": "window_filter", + "type": "Variable" + }, + { + "desc": "Number of pixels between tiled windows", + "module": "PaperWM", + "name": "window_gap", + "type": "Variable" + }, + { + "desc": "Adds a window to layout and tiles.", + "module": "PaperWM", + "name": "addWindow", + "type": "Method" + }, + { + "desc": "Removes current window from column and places it to the right", + "module": "PaperWM", + "name": "barfWindow", + "type": "Method" + }, + { + "desc": "Binds hotkeys for PaperWM", + "module": "PaperWM", + "name": "bindHotkeys", + "type": "Method" + }, + { + "desc": "Moves current window to center of screen, without resizing.", + "module": "PaperWM", + "name": "centerWindow", + "type": "Method" + }, + { + "desc": "Resizes current window by cycling through width or height ratios.", + "module": "PaperWM", + "name": "cycleWindowSize", + "type": "Method" + }, + { + "desc": "Change focus to a nearby window", + "module": "PaperWM", + "name": "focusWindow", + "type": "Method" + }, + { + "desc": "Resizes a window without triggering a windowMoved event", + "module": "PaperWM", + "name": "moveWindow", + "type": "Method" + }, + { + "desc": "Moves the current window to a new Mission Control space", + "module": "PaperWM", + "name": "moveWindowToSpace", + "type": "Method" + }, + { + "desc": "Searches for all windows that match window filter.", + "module": "PaperWM", + "name": "refreshWindows", + "type": "Method" + }, + { + "desc": "Remove window from tiling layout", + "module": "PaperWM", + "name": "remove_window", + "type": "Method" + }, + { + "desc": "Resizes current window's width to width of screen, without adjusting height.", + "module": "PaperWM", + "name": "setWindowFullWidth", + "type": "Method" + }, + { + "desc": "Moves current window into column of windows to the left", + "module": "PaperWM", + "name": "slurpWindow", + "type": "Method" + }, + { + "desc": "Start automatic tiling of windows", + "module": "PaperWM", + "name": "start", + "type": "Method" + }, + { + "desc": "Stop automatic tiling of windows", + "module": "PaperWM", + "name": "stop", + "type": "Method" + }, + { + "desc": "Swaps window postions between current window and window in specified direction.", + "module": "PaperWM", + "name": "swapWindows", + "type": "Method" + }, + { + "desc": "Switch to a Mission Control space", + "module": "PaperWM", + "name": "switchToSpace", + "type": "Method" + }, + { + "desc": "Tile a column of windows", + "module": "PaperWM", + "name": "tileColumn", + "type": "Method" + }, + { + "desc": "Tile all windows within a space", + "module": "PaperWM", + "name": "tileSpace", + "type": "Method" + }, { "desc": "Generate a password and copy to the clipboard.", "name": "PasswordGenerator", diff --git a/docs/index.html b/docs/index.html index a9f4c1a9..7bee12b6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -327,6 +327,11 @@

API documentation

OBS

Control OBS and react to its events, via the obs-websocket plugin.

+ + + + PaperWM +

A scrolling window manager. Inspired by PaperWM Gnome extension.

diff --git a/docs/templated_docs.json b/docs/templated_docs.json index 053d22f8..e7ffb747 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -13219,6 +13219,1024 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "PaperWM:addWindow(add_window)", + "def_gfm": "PaperWM:addWindow(add_window)", + "desc": "Adds a window to layout and tiles.", + "desc_gfm": "

Adds a window to layout and tiles.

\n", + "doc": "Adds a window to layout and tiles.\n\nParameters:\n * add_window - An hs.window\n\nReturns:\n * The hs.spaces space for added window or nil if window not added.", + "doc_gfm": "

Adds a window to layout and tiles.

\n

Parameters:

\n
    \n
  • add_window - An hs.window
  • \n
\n

Returns:

\n
    \n
  • The hs.spaces space for added window or nil if window not added.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "594", + "name": "addWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * add_window - An hs.window" + ], + "parameters_gfm": "
    \n
  • add_window - An hs.window
  • \n
\n", + "returns": [ + " * The hs.spaces space for added window or nil if window not added." + ], + "returns_gfm": "
    \n
  • The hs.spaces space for added window or nil if window not added.
  • \n
\n", + "signature": "PaperWM:addWindow(add_window)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:barfWindow()", + "def_gfm": "PaperWM:barfWindow()", + "desc": "Removes current window from column and places it to the right", + "desc_gfm": "

Removes current window from column and places it to the right

\n", + "doc": "Removes current window from column and places it to the right\n\nParameters:\n * None", + "doc_gfm": "

Removes current window from column and places it to the right

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1026", + "name": "barfWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:barfWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.bindHotkeys(mapping)", + "def_gfm": "PaperWM.bindHotkeys(mapping)", + "desc": "Binds hotkeys for PaperWM", + "desc_gfm": "

Binds hotkeys for PaperWM

\n", + "doc": "Binds hotkeys for PaperWM\n\nParameters:\n * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9", + "doc_gfm": "

Binds hotkeys for PaperWM

\n

Parameters:

\n
    \n
  • mapping - A table containing hotkey modifer/key details for the following items:
  • \n
  • stop_events - Stop automatic tiling
  • \n
  • focus_left - Focus window to left of current window
  • \n
  • focus_right - Focus window to right of current window
  • \n
  • focus_up - Focus window to up of current window
  • \n
  • focus_down - Focus window to down of current window
  • \n
  • swap_left - Swap positions of window to the left and current window
  • \n
  • swap_right - Swap positions of window to the right and current window
  • \n
  • swap_up - Swap positions of window above and current window
  • \n
  • swap_down - Swap positions of window below and current window
  • \n
  • center_window - Move current window to center of screen
  • \n
  • full_width - Resize width of current window to width of screen
  • \n
  • cycle_width - Toggle through preset window widths
  • \n
  • cycle_height - Toggle through preset window heights
  • \n
  • slurp_in - Move current window into column to the left
  • \n
  • barf_out - Remove current window from column and place to the right
  • \n
  • switch_space_1 - Switch to Mission Control space 1
  • \n
  • switch_space_2 - Switch to Mission Control space 2
  • \n
  • switch_space_3 - Switch to Mission Control space 3
  • \n
  • switch_space_4 - Switch to Mission Control space 4
  • \n
  • switch_space_5 - Switch to Mission Control space 5
  • \n
  • switch_space_6 - Switch to Mission Control space 6
  • \n
  • switch_space_7 - Switch to Mission Control space 7
  • \n
  • switch_space_8 - Switch to Mission Control space 8
  • \n
  • switch_space_9 - Switch to Mission Control space 9
  • \n
  • move_window_1 - Move current window to Mission Control space 1
  • \n
  • move_window_2 - Move current window to Mission Control space 2
  • \n
  • move_window_3 - Move current window to Mission Control space 3
  • \n
  • move_window_4 - Move current window to Mission Control space 4
  • \n
  • move_window_5 - Move current window to Mission Control space 5
  • \n
  • move_window_6 - Move current window to Mission Control space 6
  • \n
  • move_window_7 - Move current window to Mission Control space 7
  • \n
  • move_window_8 - Move current window to Mission Control space 8
  • \n
  • move_window_9 - Move current window to Mission Control space 9
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "275", + "name": "bindHotkeys", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9" + ], + "parameters_gfm": "
    \n
  • mapping - A table containing hotkey modifer/key details for the following items:
      \n
    • stop_events - Stop automatic tiling
    • \n
    • focus_left - Focus window to left of current window
    • \n
    • focus_right - Focus window to right of current window
    • \n
    • focus_up - Focus window to up of current window
    • \n
    • focus_down - Focus window to down of current window
    • \n
    • swap_left - Swap positions of window to the left and current window
    • \n
    • swap_right - Swap positions of window to the right and current window
    • \n
    • swap_up - Swap positions of window above and current window
    • \n
    • swap_down - Swap positions of window below and current window
    • \n
    • center_window - Move current window to center of screen
    • \n
    • full_width - Resize width of current window to width of screen
    • \n
    • cycle_width - Toggle through preset window widths
    • \n
    • cycle_height - Toggle through preset window heights
    • \n
    • slurp_in - Move current window into column to the left
    • \n
    • barf_out - Remove current window from column and place to the right
    • \n
    • switch_space_1 - Switch to Mission Control space 1
    • \n
    • switch_space_2 - Switch to Mission Control space 2
    • \n
    • switch_space_3 - Switch to Mission Control space 3
    • \n
    • switch_space_4 - Switch to Mission Control space 4
    • \n
    • switch_space_5 - Switch to Mission Control space 5
    • \n
    • switch_space_6 - Switch to Mission Control space 6
    • \n
    • switch_space_7 - Switch to Mission Control space 7
    • \n
    • switch_space_8 - Switch to Mission Control space 8
    • \n
    • switch_space_9 - Switch to Mission Control space 9
    • \n
    • move_window_1 - Move current window to Mission Control space 1
    • \n
    • move_window_2 - Move current window to Mission Control space 2
    • \n
    • move_window_3 - Move current window to Mission Control space 3
    • \n
    • move_window_4 - Move current window to Mission Control space 4
    • \n
    • move_window_5 - Move current window to Mission Control space 5
    • \n
    • move_window_6 - Move current window to Mission Control space 6
    • \n
    • move_window_7 - Move current window to Mission Control space 7
    • \n
    • move_window_8 - Move current window to Mission Control space 8
    • \n
    • move_window_9 - Move current window to Mission Control space 9
    • \n
    \n
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM.bindHotkeys(mapping)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:centerWindow()", + "def_gfm": "PaperWM:centerWindow()", + "desc": "Moves current window to center of screen, without resizing.", + "desc_gfm": "

Moves current window to center of screen, without resizing.

\n", + "doc": "Moves current window to center of screen, without resizing.\n\nParameters:\n * None", + "doc_gfm": "

Moves current window to center of screen, without resizing.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "860", + "name": "centerWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:centerWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:cycleWindowSize(direction)", + "def_gfm": "PaperWM:cycleWindowSize(direction)", + "desc": "Resizes current window by cycling through width or height ratios.", + "desc_gfm": "

Resizes current window by cycling through width or height ratios.

\n", + "doc": "Resizes current window by cycling through width or height ratios.\n\nParameters:\n * direction - One of Direction { WIDTH, HEIGHT }", + "doc_gfm": "

Resizes current window by cycling through width or height ratios.

\n

Parameters:

\n
    \n
  • direction - One of Direction { WIDTH, HEIGHT }
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "907", + "name": "cycleWindowSize", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * direction - One of Direction { WIDTH, HEIGHT }" + ], + "parameters_gfm": "
    \n
  • direction - One of Direction { WIDTH, HEIGHT }
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:cycleWindowSize(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:focusWindow(direction, focused_index)", + "def_gfm": "PaperWM:focusWindow(direction, focused_index)", + "desc": "Change focus to a nearby window", + "desc_gfm": "

Change focus to a nearby window

\n", + "doc": "Change focus to a nearby window\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }\n * focused_index - The coordinates of the current window in the tiling layout\n\nReturns:\n * A boolean. True if a new window was focused. False if no nearby window\n was found in that direction.", + "doc_gfm": "

Change focus to a nearby window

\n

Parameters:

\n
    \n
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • \n
  • focused_index - The coordinates of the current window in the tiling layout
  • \n
\n

Returns:

\n
    \n
  • A boolean. True if a new window was focused. False if no nearby window\nwas found in that direction.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "699", + "name": "focusWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + " * focused_index - The coordinates of the current window in the tiling layout" + ], + "parameters_gfm": "
    \n
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • \n
  • focused_index - The coordinates of the current window in the tiling layout
  • \n
\n", + "returns": [ + " * A boolean. True if a new window was focused. False if no nearby window", + " was found in that direction." + ], + "returns_gfm": "
    \n
  • A boolean. True if a new window was focused. False if no nearby window\nwas found in that direction.
  • \n
\n", + "signature": "PaperWM:focusWindow(direction, focused_index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM::moveWindow(window, frame)", + "def_gfm": "PaperWM::moveWindow(window, frame)", + "desc": "Resizes a window without triggering a windowMoved event", + "desc_gfm": "

Resizes a window without triggering a windowMoved event

\n", + "doc": "Resizes a window without triggering a windowMoved event\n\nParameters:\n * window - An hs.window\n * frame - An hs.geometry.rect for the windows new frame size.", + "doc_gfm": "

Resizes a window without triggering a windowMoved event

\n

Parameters:

\n
    \n
  • window - An hs.window
  • \n
  • frame - An hs.geometry.rect for the windows new frame size.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1147", + "name": "moveWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * window - An hs.window", + " * frame - An hs.geometry.rect for the windows new frame size." + ], + "parameters_gfm": "
    \n
  • window - An hs.window
  • \n
  • frame - An hs.geometry.rect for the windows new frame size.
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM::moveWindow(window, frame)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:moveWindowToSpace(index)", + "def_gfm": "PaperWM:moveWindowToSpace(index)", + "desc": "Moves the current window to a new Mission Control space", + "desc_gfm": "

Moves the current window to a new Mission Control space

\n", + "doc": "Moves the current window to a new Mission Control space\n\nParameters:\n * index - The space number", + "doc_gfm": "

Moves the current window to a new Mission Control space

\n

Parameters:

\n
    \n
  • index - The space number
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1096", + "name": "moveWindowToSpace", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * index - The space number" + ], + "parameters_gfm": "
    \n
  • index - The space number
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:moveWindowToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:refreshWindows()", + "def_gfm": "PaperWM:refreshWindows()", + "desc": "Searches for all windows that match window filter.", + "desc_gfm": "

Searches for all windows that match window filter.

\n", + "doc": "Searches for all windows that match window filter.\n\nParameters:\n * None\n\nReturns:\n * A boolean, true if the layout needs to be re-tiled, false if no change.", + "doc_gfm": "

Searches for all windows that match window filter.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • A boolean, true if the layout needs to be re-tiled, false if no change.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "563", + "name": "refreshWindows", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * A boolean, true if the layout needs to be re-tiled, false if no change." + ], + "returns_gfm": "
    \n
  • A boolean, true if the layout needs to be re-tiled, false if no change.
  • \n
\n", + "signature": "PaperWM:refreshWindows()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "def_gfm": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "desc": "Remove window from tiling layout", + "desc_gfm": "

Remove window from tiling layout

\n", + "doc": "Remove window from tiling layout\n\nParameters:\n * remove_window - A hs.window to remove from tiling layout\n * skip_new_window_focus - A boolean. True if a nearby window should not be\n focused after current window is removed.\n\nReturns:\n * The hs.spaces space for removed window.", + "doc_gfm": "

Remove window from tiling layout

\n

Parameters:

\n
    \n
  • remove_window - A hs.window to remove from tiling layout
  • \n
  • skip_new_window_focus - A boolean. True if a nearby window should not be\n focused after current window is removed.
  • \n
\n

Returns:

\n
    \n
  • The hs.spaces space for removed window.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "652", + "name": "remove_window", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * remove_window - A hs.window to remove from tiling layout", + " * skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed." + ], + "parameters_gfm": "
    \n
  • remove_window - A hs.window to remove from tiling layout
  • \n
  • skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed.
  • \n
\n", + "returns": [ + " * The hs.spaces space for removed window." + ], + "returns_gfm": "
    \n
  • The hs.spaces space for removed window.
  • \n
\n", + "signature": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:setWindowFullWidth()", + "def_gfm": "PaperWM:setWindowFullWidth()", + "desc": "Resizes current window's width to width of screen, without adjusting height.", + "desc_gfm": "

Resizes current window's width to width of screen, without adjusting height.

\n", + "doc": "Resizes current window's width to width of screen, without adjusting height.\n\nParameters:\n * None", + "doc_gfm": "

Resizes current window's width to width of screen, without adjusting height.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "885", + "name": "setWindowFullWidth", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:setWindowFullWidth()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:slurpWindow()", + "def_gfm": "PaperWM:slurpWindow()", + "desc": "Moves current window into column of windows to the left", + "desc_gfm": "

Moves current window into column of windows to the left

\n", + "doc": "Moves current window into column of windows to the left\n\nParameters:\n * None", + "doc_gfm": "

Moves current window into column of windows to the left

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "961", + "name": "slurpWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:slurpWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:start()", + "def_gfm": "PaperWM:start()", + "desc": "Start automatic tiling of windows", + "desc_gfm": "

Start automatic tiling of windows

\n", + "doc": "Start automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "doc_gfm": "

Start automatic tiling of windows

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The PaperWM object
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "354", + "name": "start", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * The PaperWM object" + ], + "returns_gfm": "
    \n
  • The PaperWM object
  • \n
\n", + "signature": "PaperWM:start()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:stop()", + "def_gfm": "PaperWM:stop()", + "desc": "Stop automatic tiling of windows", + "desc_gfm": "

Stop automatic tiling of windows

\n", + "doc": "Stop automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "doc_gfm": "

Stop automatic tiling of windows

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The PaperWM object
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "391", + "name": "stop", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * The PaperWM object" + ], + "returns_gfm": "
    \n
  • The PaperWM object
  • \n
\n", + "signature": "PaperWM:stop()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:swapWindows(direction)", + "def_gfm": "PaperWM:swapWindows(direction)", + "desc": "Swaps window postions between current window and window in specified direction.", + "desc_gfm": "

Swaps window postions between current window and window in specified direction.

\n", + "doc": "Swaps window postions between current window and window in specified direction.\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + "doc_gfm": "

Swaps window postions between current window and window in specified direction.

\n

Parameters:

\n
    \n
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "749", + "name": "swapWindows", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }" + ], + "parameters_gfm": "
    \n
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:swapWindows(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:switchToSpace(index)", + "def_gfm": "PaperWM:switchToSpace(index)", + "desc": "Switch to a Mission Control space", + "desc_gfm": "

Switch to a Mission Control space

\n", + "doc": "Switch to a Mission Control space\n\nParameters:\n * index - The space number", + "doc_gfm": "

Switch to a Mission Control space

\n

Parameters:

\n
    \n
  • index - The space number
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1080", + "name": "switchToSpace", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * index - The space number" + ], + "parameters_gfm": "
    \n
  • index - The space number
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:switchToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "def_gfm": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "desc": "Tile a column of windows", + "desc_gfm": "

Tile a column of windows

\n", + "doc": "Tile a column of windows\n\nParameters:\n * windows - A list of hs.windows.\n * bounds - An hs.geometry.rect. The area for this column to fill.\n * h - The height for each window in column.\n * w - The width for each window in column.\n * id - A hs.window.id() for a specific window in column.\n * h4id - The height for a window matching id in column.\n\nNotes:\n * The h, w, id, and h4id parameters are optional. The height and width of\n all windows will be calculated and set to fill column bounds.\n * If bounds width is not specified, all windows in column will be resized\n to width of first window.\n\nReturns:\n * The width of the column", + "doc_gfm": "

Tile a column of windows

\n

Parameters:

\n
    \n
  • windows - A list of hs.windows.
  • \n
  • bounds - An hs.geometry.rect. The area for this column to fill.
  • \n
  • h - The height for each window in column.
  • \n
  • w - The width for each window in column.
  • \n
  • id - A hs.window.id() for a specific window in column.
  • \n
  • h4id - The height for a window matching id in column.
  • \n
\n

Notes:

\n
    \n
  • The h, w, id, and h4id parameters are optional. The height and width of\nall windows will be calculated and set to fill column bounds.
  • \n
  • If bounds width is not specified, all windows in column will be resized\nto width of first window.
  • \n
\n

Returns:

\n
    \n
  • The width of the column
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "408", + "name": "tileColumn", + "notes": [ + " * The h, w, id, and h4id parameters are optional. The height and width of", + " all windows will be calculated and set to fill column bounds.", + " * If bounds width is not specified, all windows in column will be resized", + " to width of first window." + ], + "notes_gfm": "
    \n
  • The h, w, id, and h4id parameters are optional. The height and width of\nall windows will be calculated and set to fill column bounds.
  • \n
  • If bounds width is not specified, all windows in column will be resized\nto width of first window.
  • \n
\n", + "parameters": [ + " * windows - A list of hs.windows.", + " * bounds - An hs.geometry.rect. The area for this column to fill.", + " * h - The height for each window in column.", + " * w - The width for each window in column.", + " * id - A hs.window.id() for a specific window in column.", + " * h4id - The height for a window matching id in column." + ], + "parameters_gfm": "
    \n
  • windows - A list of hs.windows.
  • \n
  • bounds - An hs.geometry.rect. The area for this column to fill.
  • \n
  • h - The height for each window in column.
  • \n
  • w - The width for each window in column.
  • \n
  • id - A hs.window.id() for a specific window in column.
  • \n
  • h4id - The height for a window matching id in column.
  • \n
\n", + "returns": [ + " * The width of the column" + ], + "returns_gfm": "
    \n
  • The width of the column
  • \n
\n", + "signature": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileSpace(space)", + "def_gfm": "PaperWM:tileSpace(space)", + "desc": "Tile all windows within a space", + "desc_gfm": "

Tile all windows within a space

\n", + "doc": "Tile all windows within a space\n\nParameters:\n * space - A hs.spaces space.", + "doc_gfm": "

Tile all windows within a space

\n

Parameters:

\n
    \n
  • space - A hs.spaces space.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "460", + "name": "tileSpace", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * space - A hs.spaces space." + ], + "parameters_gfm": "
    \n
  • space - A hs.spaces space.
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:tileSpace(space)", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [ + { + "def": "PaperWM.default_hotkeys", + "def_gfm": "PaperWM.default_hotkeys", + "desc": "Default hotkeys for moving / resizing windows", + "desc_gfm": "

Default hotkeys for moving / resizing windows

\n", + "doc": "Default hotkeys for moving / resizing windows", + "doc_gfm": "

Default hotkeys for moving / resizing windows

\n", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "111", + "name": "default_hotkeys", + "signature": "PaperWM.default_hotkeys", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.logger", + "def_gfm": "PaperWM.logger", + "desc": "Logger object. Can be accessed to set default log level.", + "desc_gfm": "

Logger object. Can be accessed to set default log level.

\n", + "doc": "Logger object. Can be accessed to set default log level.", + "doc_gfm": "

Logger object. Can be accessed to set default log level.

\n", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "165", + "name": "logger", + "signature": "PaperWM.logger", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_filter", + "def_gfm": "PaperWM.window_filter", + "desc": "Windows captured by this filter are automatically tiled and managed", + "desc_gfm": "

Windows captured by this filter are automatically tiled and managed

\n", + "doc": "Windows captured by this filter are automatically tiled and managed", + "doc_gfm": "

Windows captured by this filter are automatically tiled and managed

\n", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "150", + "name": "window_filter", + "signature": "PaperWM.window_filter", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_gap", + "def_gfm": "PaperWM.window_gap", + "desc": "Number of pixels between tiled windows", + "desc_gfm": "

Number of pixels between tiled windows

\n", + "doc": "Number of pixels between tiled windows", + "doc_gfm": "

Number of pixels between tiled windows

\n", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "160", + "name": "window_gap", + "signature": "PaperWM.window_gap", + "stripped_doc": "", + "type": "Variable" + } + ], + "desc": "A scrolling window manager. Inspired by PaperWM Gnome extension.", + "desc_gfm": "

A scrolling window manager. Inspired by PaperWM Gnome extension.

\n", + "doc": "A scrolling window manager. Inspired by PaperWM Gnome extension.\n\n# Usage\n\n`PaperWM:start()` will begin automatically tiling new and existing windows.\n`PaperWM:stop()` will release control over windows.\n`PaperWM::bindHotkeys()` will move / resize windows using keyboard shortcuts.\n\nHere is an example Hammerspoon config:\n\n```\nPaperWM = hs.loadSpoon(\"PaperWM\")\nPaperWM:bindHotkeys({\n -- switch to a new focused window in tiled grid\n focus_left = {{\"ctrl\", \"alt\", \"cmd\"}, \"left\"},\n focus_right = {{\"ctrl\", \"alt\", \"cmd\"}, \"right\"},\n focus_up = {{\"ctrl\", \"alt\", \"cmd\"}, \"up\"},\n focus_down = {{\"ctrl\", \"alt\", \"cmd\"}, \"down\"},\n\n -- move windows around in tiled grid\n swap_left = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"left\"},\n swap_right = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"right\"},\n swap_up = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"up\"},\n swap_down = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"down\"},\n\n -- position and resize focused window\n center_window = {{\"ctrl\", \"alt\", \"cmd\"}, \"c\"},\n full_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"f\"},\n cycle_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"r\"},\n cycle_height = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"r\"},\n\n -- move focused window into / out of a column\n slurp_in = {{\"ctrl\", \"alt\", \"cmd\"}, \"i\"},\n barf_out = {{\"ctrl\", \"alt\", \"cmd\"}, \"o\"},\n\n -- switch to a new Mission Control space\n switch_space_1 = {{\"ctrl\", \"alt\", \"cmd\"}, \"1\"},\n switch_space_2 = {{\"ctrl\", \"alt\", \"cmd\"}, \"2\"},\n switch_space_3 = {{\"ctrl\", \"alt\", \"cmd\"}, \"3\"},\n switch_space_4 = {{\"ctrl\", \"alt\", \"cmd\"}, \"4\"},\n switch_space_5 = {{\"ctrl\", \"alt\", \"cmd\"}, \"5\"},\n switch_space_6 = {{\"ctrl\", \"alt\", \"cmd\"}, \"6\"},\n switch_space_7 = {{\"ctrl\", \"alt\", \"cmd\"}, \"7\"},\n switch_space_8 = {{\"ctrl\", \"alt\", \"cmd\"}, \"8\"},\n switch_space_9 = {{\"ctrl\", \"alt\", \"cmd\"}, \"9\"},\n\n -- move focused window to a new space and tile\n move_window_1 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"1\"},\n move_window_2 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"2\"},\n move_window_3 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"3\"},\n move_window_4 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"4\"},\n move_window_5 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"5\"},\n move_window_6 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"6\"},\n move_window_7 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"7\"},\n move_window_8 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"8\"},\n move_window_9 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"9\"}\n})\nPaperWM:start()\n```\n\nUse `PaperWM:bindHotkeys(PaperWM.default_hotkeys)` for defaults.\n\nSet `PaperWM.window_gap` to the number of pixels to space between windows and\nthe top and bottom screen edges.\n\nOverwrite `PaperWM.window_filter` to ignore specific applications. For example:\n\n```\nPaperWM.window_filter = PaperWM.window_filter:setAppFilter(\"Finder\", false)\nPaperWM:start() -- restart for new window filter to take effect\n```\n\n# Limitations\n\nUnder System Preferences -> Mission Control, unselect \"Automatically\nrearrange Spaces based on most recent use\" and select \"Displays have separate\nSpaces\".\n\nMacOS does not allow a window to be moved fully off-screen. Windows that would\nbe tiled off-screen are placed in a margin on the left and right edge of the\nscreen. They are still visible and clickable.\n\nIt's difficult to detect when a window is dragged from one space or screen to\nanother. Use the move_window_N commands to move windows between spaces and\nscreens.\n\nArrange screens vertically to prevent windows from bleeding into other screens.\n\n\nDownload: [https://github.com/mogenson/PaperWM.spoon](https://github.com/mogenson/PaperWM.spoon)", + "doc_gfm": "

A scrolling window manager. Inspired by PaperWM Gnome extension.

\n

Usage

\n

PaperWM:start() will begin automatically tiling new and existing windows.\nPaperWM:stop() will release control over windows.\nPaperWM::bindHotkeys() will move / resize windows using keyboard shortcuts.

\n

Here is an example Hammerspoon config:

\n\n
PaperWM = hs.loadSpoon("PaperWM")\nPaperWM:bindHotkeys({\n    -- switch to a new focused window in tiled grid\n    focus_left  = {{"ctrl", "alt", "cmd"}, "left"},\n    focus_right = {{"ctrl", "alt", "cmd"}, "right"},\n    focus_up    = {{"ctrl", "alt", "cmd"}, "up"},\n    focus_down  = {{"ctrl", "alt", "cmd"}, "down"},\n\n    -- move windows around in tiled grid\n    swap_left  = {{"ctrl", "alt", "cmd", "shift"}, "left"},\n    swap_right = {{"ctrl", "alt", "cmd", "shift"}, "right"},\n    swap_up    = {{"ctrl", "alt", "cmd", "shift"}, "up"},\n    swap_down  = {{"ctrl", "alt", "cmd", "shift"}, "down"},\n\n    -- position and resize focused window\n    center_window = {{"ctrl", "alt", "cmd"}, "c"},\n    full_width    = {{"ctrl", "alt", "cmd"}, "f"},\n    cycle_width   = {{"ctrl", "alt", "cmd"}, "r"},\n    cycle_height  = {{"ctrl", "alt", "cmd", "shift"}, "r"},\n\n    -- move focused window into / out of a column\n    slurp_in = {{"ctrl", "alt", "cmd"}, "i"},\n    barf_out = {{"ctrl", "alt", "cmd"}, "o"},\n\n    -- switch to a new Mission Control space\n    switch_space_1 = {{"ctrl", "alt", "cmd"}, "1"},\n    switch_space_2 = {{"ctrl", "alt", "cmd"}, "2"},\n    switch_space_3 = {{"ctrl", "alt", "cmd"}, "3"},\n    switch_space_4 = {{"ctrl", "alt", "cmd"}, "4"},\n    switch_space_5 = {{"ctrl", "alt", "cmd"}, "5"},\n    switch_space_6 = {{"ctrl", "alt", "cmd"}, "6"},\n    switch_space_7 = {{"ctrl", "alt", "cmd"}, "7"},\n    switch_space_8 = {{"ctrl", "alt", "cmd"}, "8"},\n    switch_space_9 = {{"ctrl", "alt", "cmd"}, "9"},\n\n    -- move focused window to a new space and tile\n    move_window_1 = {{"ctrl", "alt", "cmd", "shift"}, "1"},\n    move_window_2 = {{"ctrl", "alt", "cmd", "shift"}, "2"},\n    move_window_3 = {{"ctrl", "alt", "cmd", "shift"}, "3"},\n    move_window_4 = {{"ctrl", "alt", "cmd", "shift"}, "4"},\n    move_window_5 = {{"ctrl", "alt", "cmd", "shift"}, "5"},\n    move_window_6 = {{"ctrl", "alt", "cmd", "shift"}, "6"},\n    move_window_7 = {{"ctrl", "alt", "cmd", "shift"}, "7"},\n    move_window_8 = {{"ctrl", "alt", "cmd", "shift"}, "8"},\n    move_window_9 = {{"ctrl", "alt", "cmd", "shift"}, "9"}\n})\nPaperWM:start()\n
\n

Use PaperWM:bindHotkeys(PaperWM.default_hotkeys) for defaults.

\n

Set PaperWM.window_gap to the number of pixels to space between windows and\nthe top and bottom screen edges.

\n

Overwrite PaperWM.window_filter to ignore specific applications. For example:

\n\n
PaperWM.window_filter = PaperWM.window_filter:setAppFilter("Finder", false)\nPaperWM:start() -- restart for new window filter to take effect\n
\n

Limitations

\n

Under System Preferences -> Mission Control, unselect "Automatically\nrearrange Spaces based on most recent use" and select "Displays have separate\nSpaces".

\n

MacOS does not allow a window to be moved fully off-screen. Windows that would\nbe tiled off-screen are placed in a margin on the left and right edge of the\nscreen. They are still visible and clickable.

\n

It's difficult to detect when a window is dragged from one space or screen to\nanother. Use the move_window_N commands to move windows between spaces and\nscreens.

\n

Arrange screens vertically to prevent windows from bleeding into other screens.

\n

Download: https://github.com/mogenson/PaperWM.spoon

\n", + "items": [ + { + "def": "PaperWM:addWindow(add_window)", + "def_gfm": "PaperWM:addWindow(add_window)", + "desc": "Adds a window to layout and tiles.", + "desc_gfm": "

Adds a window to layout and tiles.

\n", + "doc": "Adds a window to layout and tiles.\n\nParameters:\n * add_window - An hs.window\n\nReturns:\n * The hs.spaces space for added window or nil if window not added.", + "doc_gfm": "

Adds a window to layout and tiles.

\n

Parameters:

\n
    \n
  • add_window - An hs.window
  • \n
\n

Returns:

\n
    \n
  • The hs.spaces space for added window or nil if window not added.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "594", + "name": "addWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * add_window - An hs.window" + ], + "parameters_gfm": "
    \n
  • add_window - An hs.window
  • \n
\n", + "returns": [ + " * The hs.spaces space for added window or nil if window not added." + ], + "returns_gfm": "
    \n
  • The hs.spaces space for added window or nil if window not added.
  • \n
\n", + "signature": "PaperWM:addWindow(add_window)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:barfWindow()", + "def_gfm": "PaperWM:barfWindow()", + "desc": "Removes current window from column and places it to the right", + "desc_gfm": "

Removes current window from column and places it to the right

\n", + "doc": "Removes current window from column and places it to the right\n\nParameters:\n * None", + "doc_gfm": "

Removes current window from column and places it to the right

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1026", + "name": "barfWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:barfWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.bindHotkeys(mapping)", + "def_gfm": "PaperWM.bindHotkeys(mapping)", + "desc": "Binds hotkeys for PaperWM", + "desc_gfm": "

Binds hotkeys for PaperWM

\n", + "doc": "Binds hotkeys for PaperWM\n\nParameters:\n * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9", + "doc_gfm": "

Binds hotkeys for PaperWM

\n

Parameters:

\n
    \n
  • mapping - A table containing hotkey modifer/key details for the following items:
  • \n
  • stop_events - Stop automatic tiling
  • \n
  • focus_left - Focus window to left of current window
  • \n
  • focus_right - Focus window to right of current window
  • \n
  • focus_up - Focus window to up of current window
  • \n
  • focus_down - Focus window to down of current window
  • \n
  • swap_left - Swap positions of window to the left and current window
  • \n
  • swap_right - Swap positions of window to the right and current window
  • \n
  • swap_up - Swap positions of window above and current window
  • \n
  • swap_down - Swap positions of window below and current window
  • \n
  • center_window - Move current window to center of screen
  • \n
  • full_width - Resize width of current window to width of screen
  • \n
  • cycle_width - Toggle through preset window widths
  • \n
  • cycle_height - Toggle through preset window heights
  • \n
  • slurp_in - Move current window into column to the left
  • \n
  • barf_out - Remove current window from column and place to the right
  • \n
  • switch_space_1 - Switch to Mission Control space 1
  • \n
  • switch_space_2 - Switch to Mission Control space 2
  • \n
  • switch_space_3 - Switch to Mission Control space 3
  • \n
  • switch_space_4 - Switch to Mission Control space 4
  • \n
  • switch_space_5 - Switch to Mission Control space 5
  • \n
  • switch_space_6 - Switch to Mission Control space 6
  • \n
  • switch_space_7 - Switch to Mission Control space 7
  • \n
  • switch_space_8 - Switch to Mission Control space 8
  • \n
  • switch_space_9 - Switch to Mission Control space 9
  • \n
  • move_window_1 - Move current window to Mission Control space 1
  • \n
  • move_window_2 - Move current window to Mission Control space 2
  • \n
  • move_window_3 - Move current window to Mission Control space 3
  • \n
  • move_window_4 - Move current window to Mission Control space 4
  • \n
  • move_window_5 - Move current window to Mission Control space 5
  • \n
  • move_window_6 - Move current window to Mission Control space 6
  • \n
  • move_window_7 - Move current window to Mission Control space 7
  • \n
  • move_window_8 - Move current window to Mission Control space 8
  • \n
  • move_window_9 - Move current window to Mission Control space 9
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "275", + "name": "bindHotkeys", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * mapping - A table containing hotkey modifer/key details for the following items:\n * stop_events - Stop automatic tiling\n * focus_left - Focus window to left of current window\n * focus_right - Focus window to right of current window\n * focus_up - Focus window to up of current window\n * focus_down - Focus window to down of current window\n * swap_left - Swap positions of window to the left and current window\n * swap_right - Swap positions of window to the right and current window\n * swap_up - Swap positions of window above and current window\n * swap_down - Swap positions of window below and current window\n * center_window - Move current window to center of screen\n * full_width - Resize width of current window to width of screen\n * cycle_width - Toggle through preset window widths\n * cycle_height - Toggle through preset window heights\n * slurp_in - Move current window into column to the left\n * barf_out - Remove current window from column and place to the right\n * switch_space_1 - Switch to Mission Control space 1\n * switch_space_2 - Switch to Mission Control space 2\n * switch_space_3 - Switch to Mission Control space 3\n * switch_space_4 - Switch to Mission Control space 4\n * switch_space_5 - Switch to Mission Control space 5\n * switch_space_6 - Switch to Mission Control space 6\n * switch_space_7 - Switch to Mission Control space 7\n * switch_space_8 - Switch to Mission Control space 8\n * switch_space_9 - Switch to Mission Control space 9\n * move_window_1 - Move current window to Mission Control space 1\n * move_window_2 - Move current window to Mission Control space 2\n * move_window_3 - Move current window to Mission Control space 3\n * move_window_4 - Move current window to Mission Control space 4\n * move_window_5 - Move current window to Mission Control space 5\n * move_window_6 - Move current window to Mission Control space 6\n * move_window_7 - Move current window to Mission Control space 7\n * move_window_8 - Move current window to Mission Control space 8\n * move_window_9 - Move current window to Mission Control space 9" + ], + "parameters_gfm": "
    \n
  • mapping - A table containing hotkey modifer/key details for the following items:
      \n
    • stop_events - Stop automatic tiling
    • \n
    • focus_left - Focus window to left of current window
    • \n
    • focus_right - Focus window to right of current window
    • \n
    • focus_up - Focus window to up of current window
    • \n
    • focus_down - Focus window to down of current window
    • \n
    • swap_left - Swap positions of window to the left and current window
    • \n
    • swap_right - Swap positions of window to the right and current window
    • \n
    • swap_up - Swap positions of window above and current window
    • \n
    • swap_down - Swap positions of window below and current window
    • \n
    • center_window - Move current window to center of screen
    • \n
    • full_width - Resize width of current window to width of screen
    • \n
    • cycle_width - Toggle through preset window widths
    • \n
    • cycle_height - Toggle through preset window heights
    • \n
    • slurp_in - Move current window into column to the left
    • \n
    • barf_out - Remove current window from column and place to the right
    • \n
    • switch_space_1 - Switch to Mission Control space 1
    • \n
    • switch_space_2 - Switch to Mission Control space 2
    • \n
    • switch_space_3 - Switch to Mission Control space 3
    • \n
    • switch_space_4 - Switch to Mission Control space 4
    • \n
    • switch_space_5 - Switch to Mission Control space 5
    • \n
    • switch_space_6 - Switch to Mission Control space 6
    • \n
    • switch_space_7 - Switch to Mission Control space 7
    • \n
    • switch_space_8 - Switch to Mission Control space 8
    • \n
    • switch_space_9 - Switch to Mission Control space 9
    • \n
    • move_window_1 - Move current window to Mission Control space 1
    • \n
    • move_window_2 - Move current window to Mission Control space 2
    • \n
    • move_window_3 - Move current window to Mission Control space 3
    • \n
    • move_window_4 - Move current window to Mission Control space 4
    • \n
    • move_window_5 - Move current window to Mission Control space 5
    • \n
    • move_window_6 - Move current window to Mission Control space 6
    • \n
    • move_window_7 - Move current window to Mission Control space 7
    • \n
    • move_window_8 - Move current window to Mission Control space 8
    • \n
    • move_window_9 - Move current window to Mission Control space 9
    • \n
    \n
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM.bindHotkeys(mapping)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:centerWindow()", + "def_gfm": "PaperWM:centerWindow()", + "desc": "Moves current window to center of screen, without resizing.", + "desc_gfm": "

Moves current window to center of screen, without resizing.

\n", + "doc": "Moves current window to center of screen, without resizing.\n\nParameters:\n * None", + "doc_gfm": "

Moves current window to center of screen, without resizing.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "860", + "name": "centerWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:centerWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:cycleWindowSize(direction)", + "def_gfm": "PaperWM:cycleWindowSize(direction)", + "desc": "Resizes current window by cycling through width or height ratios.", + "desc_gfm": "

Resizes current window by cycling through width or height ratios.

\n", + "doc": "Resizes current window by cycling through width or height ratios.\n\nParameters:\n * direction - One of Direction { WIDTH, HEIGHT }", + "doc_gfm": "

Resizes current window by cycling through width or height ratios.

\n

Parameters:

\n
    \n
  • direction - One of Direction { WIDTH, HEIGHT }
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "907", + "name": "cycleWindowSize", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * direction - One of Direction { WIDTH, HEIGHT }" + ], + "parameters_gfm": "
    \n
  • direction - One of Direction { WIDTH, HEIGHT }
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:cycleWindowSize(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.default_hotkeys", + "def_gfm": "PaperWM.default_hotkeys", + "desc": "Default hotkeys for moving / resizing windows", + "desc_gfm": "

Default hotkeys for moving / resizing windows

\n", + "doc": "Default hotkeys for moving / resizing windows", + "doc_gfm": "

Default hotkeys for moving / resizing windows

\n", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "111", + "name": "default_hotkeys", + "signature": "PaperWM.default_hotkeys", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM:focusWindow(direction, focused_index)", + "def_gfm": "PaperWM:focusWindow(direction, focused_index)", + "desc": "Change focus to a nearby window", + "desc_gfm": "

Change focus to a nearby window

\n", + "doc": "Change focus to a nearby window\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }\n * focused_index - The coordinates of the current window in the tiling layout\n\nReturns:\n * A boolean. True if a new window was focused. False if no nearby window\n was found in that direction.", + "doc_gfm": "

Change focus to a nearby window

\n

Parameters:

\n
    \n
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • \n
  • focused_index - The coordinates of the current window in the tiling layout
  • \n
\n

Returns:

\n
    \n
  • A boolean. True if a new window was focused. False if no nearby window\nwas found in that direction.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "699", + "name": "focusWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + " * focused_index - The coordinates of the current window in the tiling layout" + ], + "parameters_gfm": "
    \n
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • \n
  • focused_index - The coordinates of the current window in the tiling layout
  • \n
\n", + "returns": [ + " * A boolean. True if a new window was focused. False if no nearby window", + " was found in that direction." + ], + "returns_gfm": "
    \n
  • A boolean. True if a new window was focused. False if no nearby window\nwas found in that direction.
  • \n
\n", + "signature": "PaperWM:focusWindow(direction, focused_index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.logger", + "def_gfm": "PaperWM.logger", + "desc": "Logger object. Can be accessed to set default log level.", + "desc_gfm": "

Logger object. Can be accessed to set default log level.

\n", + "doc": "Logger object. Can be accessed to set default log level.", + "doc_gfm": "

Logger object. Can be accessed to set default log level.

\n", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "165", + "name": "logger", + "signature": "PaperWM.logger", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM::moveWindow(window, frame)", + "def_gfm": "PaperWM::moveWindow(window, frame)", + "desc": "Resizes a window without triggering a windowMoved event", + "desc_gfm": "

Resizes a window without triggering a windowMoved event

\n", + "doc": "Resizes a window without triggering a windowMoved event\n\nParameters:\n * window - An hs.window\n * frame - An hs.geometry.rect for the windows new frame size.", + "doc_gfm": "

Resizes a window without triggering a windowMoved event

\n

Parameters:

\n
    \n
  • window - An hs.window
  • \n
  • frame - An hs.geometry.rect for the windows new frame size.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1147", + "name": "moveWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * window - An hs.window", + " * frame - An hs.geometry.rect for the windows new frame size." + ], + "parameters_gfm": "
    \n
  • window - An hs.window
  • \n
  • frame - An hs.geometry.rect for the windows new frame size.
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM::moveWindow(window, frame)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:moveWindowToSpace(index)", + "def_gfm": "PaperWM:moveWindowToSpace(index)", + "desc": "Moves the current window to a new Mission Control space", + "desc_gfm": "

Moves the current window to a new Mission Control space

\n", + "doc": "Moves the current window to a new Mission Control space\n\nParameters:\n * index - The space number", + "doc_gfm": "

Moves the current window to a new Mission Control space

\n

Parameters:

\n
    \n
  • index - The space number
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1096", + "name": "moveWindowToSpace", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * index - The space number" + ], + "parameters_gfm": "
    \n
  • index - The space number
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:moveWindowToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:refreshWindows()", + "def_gfm": "PaperWM:refreshWindows()", + "desc": "Searches for all windows that match window filter.", + "desc_gfm": "

Searches for all windows that match window filter.

\n", + "doc": "Searches for all windows that match window filter.\n\nParameters:\n * None\n\nReturns:\n * A boolean, true if the layout needs to be re-tiled, false if no change.", + "doc_gfm": "

Searches for all windows that match window filter.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • A boolean, true if the layout needs to be re-tiled, false if no change.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "563", + "name": "refreshWindows", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * A boolean, true if the layout needs to be re-tiled, false if no change." + ], + "returns_gfm": "
    \n
  • A boolean, true if the layout needs to be re-tiled, false if no change.
  • \n
\n", + "signature": "PaperWM:refreshWindows()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "def_gfm": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "desc": "Remove window from tiling layout", + "desc_gfm": "

Remove window from tiling layout

\n", + "doc": "Remove window from tiling layout\n\nParameters:\n * remove_window - A hs.window to remove from tiling layout\n * skip_new_window_focus - A boolean. True if a nearby window should not be\n focused after current window is removed.\n\nReturns:\n * The hs.spaces space for removed window.", + "doc_gfm": "

Remove window from tiling layout

\n

Parameters:

\n
    \n
  • remove_window - A hs.window to remove from tiling layout
  • \n
  • skip_new_window_focus - A boolean. True if a nearby window should not be\n focused after current window is removed.
  • \n
\n

Returns:

\n
    \n
  • The hs.spaces space for removed window.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "652", + "name": "remove_window", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * remove_window - A hs.window to remove from tiling layout", + " * skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed." + ], + "parameters_gfm": "
    \n
  • remove_window - A hs.window to remove from tiling layout
  • \n
  • skip_new_window_focus - A boolean. True if a nearby window should not be focused after current window is removed.
  • \n
\n", + "returns": [ + " * The hs.spaces space for removed window." + ], + "returns_gfm": "
    \n
  • The hs.spaces space for removed window.
  • \n
\n", + "signature": "PaperWM:remove_window(remove_window, skip_new_window_focus)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:setWindowFullWidth()", + "def_gfm": "PaperWM:setWindowFullWidth()", + "desc": "Resizes current window's width to width of screen, without adjusting height.", + "desc_gfm": "

Resizes current window's width to width of screen, without adjusting height.

\n", + "doc": "Resizes current window's width to width of screen, without adjusting height.\n\nParameters:\n * None", + "doc_gfm": "

Resizes current window's width to width of screen, without adjusting height.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "885", + "name": "setWindowFullWidth", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:setWindowFullWidth()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:slurpWindow()", + "def_gfm": "PaperWM:slurpWindow()", + "desc": "Moves current window into column of windows to the left", + "desc_gfm": "

Moves current window into column of windows to the left

\n", + "doc": "Moves current window into column of windows to the left\n\nParameters:\n * None", + "doc_gfm": "

Moves current window into column of windows to the left

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "961", + "name": "slurpWindow", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:slurpWindow()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:start()", + "def_gfm": "PaperWM:start()", + "desc": "Start automatic tiling of windows", + "desc_gfm": "

Start automatic tiling of windows

\n", + "doc": "Start automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "doc_gfm": "

Start automatic tiling of windows

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The PaperWM object
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "354", + "name": "start", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * The PaperWM object" + ], + "returns_gfm": "
    \n
  • The PaperWM object
  • \n
\n", + "signature": "PaperWM:start()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:stop()", + "def_gfm": "PaperWM:stop()", + "desc": "Stop automatic tiling of windows", + "desc_gfm": "

Stop automatic tiling of windows

\n", + "doc": "Stop automatic tiling of windows\n\nParameters:\n * None\n\nReturns:\n * The PaperWM object", + "doc_gfm": "

Stop automatic tiling of windows

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The PaperWM object
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "391", + "name": "stop", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * The PaperWM object" + ], + "returns_gfm": "
    \n
  • The PaperWM object
  • \n
\n", + "signature": "PaperWM:stop()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:swapWindows(direction)", + "def_gfm": "PaperWM:swapWindows(direction)", + "desc": "Swaps window postions between current window and window in specified direction.", + "desc_gfm": "

Swaps window postions between current window and window in specified direction.

\n", + "doc": "Swaps window postions between current window and window in specified direction.\n\nParameters:\n * direction - One of Direction { LEFT, RIGHT, DOWN, UP }", + "doc_gfm": "

Swaps window postions between current window and window in specified direction.

\n

Parameters:

\n
    \n
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "749", + "name": "swapWindows", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * direction - One of Direction { LEFT, RIGHT, DOWN, UP }" + ], + "parameters_gfm": "
    \n
  • direction - One of Direction { LEFT, RIGHT, DOWN, UP }
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:swapWindows(direction)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:switchToSpace(index)", + "def_gfm": "PaperWM:switchToSpace(index)", + "desc": "Switch to a Mission Control space", + "desc_gfm": "

Switch to a Mission Control space

\n", + "doc": "Switch to a Mission Control space\n\nParameters:\n * index - The space number", + "doc_gfm": "

Switch to a Mission Control space

\n

Parameters:

\n
    \n
  • index - The space number
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "1080", + "name": "switchToSpace", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * index - The space number" + ], + "parameters_gfm": "
    \n
  • index - The space number
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:switchToSpace(index)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "def_gfm": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "desc": "Tile a column of windows", + "desc_gfm": "

Tile a column of windows

\n", + "doc": "Tile a column of windows\n\nParameters:\n * windows - A list of hs.windows.\n * bounds - An hs.geometry.rect. The area for this column to fill.\n * h - The height for each window in column.\n * w - The width for each window in column.\n * id - A hs.window.id() for a specific window in column.\n * h4id - The height for a window matching id in column.\n\nNotes:\n * The h, w, id, and h4id parameters are optional. The height and width of\n all windows will be calculated and set to fill column bounds.\n * If bounds width is not specified, all windows in column will be resized\n to width of first window.\n\nReturns:\n * The width of the column", + "doc_gfm": "

Tile a column of windows

\n

Parameters:

\n
    \n
  • windows - A list of hs.windows.
  • \n
  • bounds - An hs.geometry.rect. The area for this column to fill.
  • \n
  • h - The height for each window in column.
  • \n
  • w - The width for each window in column.
  • \n
  • id - A hs.window.id() for a specific window in column.
  • \n
  • h4id - The height for a window matching id in column.
  • \n
\n

Notes:

\n
    \n
  • The h, w, id, and h4id parameters are optional. The height and width of\nall windows will be calculated and set to fill column bounds.
  • \n
  • If bounds width is not specified, all windows in column will be resized\nto width of first window.
  • \n
\n

Returns:

\n
    \n
  • The width of the column
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "408", + "name": "tileColumn", + "notes": [ + " * The h, w, id, and h4id parameters are optional. The height and width of", + " all windows will be calculated and set to fill column bounds.", + " * If bounds width is not specified, all windows in column will be resized", + " to width of first window." + ], + "notes_gfm": "
    \n
  • The h, w, id, and h4id parameters are optional. The height and width of\nall windows will be calculated and set to fill column bounds.
  • \n
  • If bounds width is not specified, all windows in column will be resized\nto width of first window.
  • \n
\n", + "parameters": [ + " * windows - A list of hs.windows.", + " * bounds - An hs.geometry.rect. The area for this column to fill.", + " * h - The height for each window in column.", + " * w - The width for each window in column.", + " * id - A hs.window.id() for a specific window in column.", + " * h4id - The height for a window matching id in column." + ], + "parameters_gfm": "
    \n
  • windows - A list of hs.windows.
  • \n
  • bounds - An hs.geometry.rect. The area for this column to fill.
  • \n
  • h - The height for each window in column.
  • \n
  • w - The width for each window in column.
  • \n
  • id - A hs.window.id() for a specific window in column.
  • \n
  • h4id - The height for a window matching id in column.
  • \n
\n", + "returns": [ + " * The width of the column" + ], + "returns_gfm": "
    \n
  • The width of the column
  • \n
\n", + "signature": "PaperWM:tileColumn(windows, bounds, h, w, id, h4id)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM:tileSpace(space)", + "def_gfm": "PaperWM:tileSpace(space)", + "desc": "Tile all windows within a space", + "desc_gfm": "

Tile all windows within a space

\n", + "doc": "Tile all windows within a space\n\nParameters:\n * space - A hs.spaces space.", + "doc_gfm": "

Tile all windows within a space

\n

Parameters:

\n
    \n
  • space - A hs.spaces space.
  • \n
\n", + "examples": [], + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "460", + "name": "tileSpace", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * space - A hs.spaces space." + ], + "parameters_gfm": "
    \n
  • space - A hs.spaces space.
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "PaperWM:tileSpace(space)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "PaperWM.window_filter", + "def_gfm": "PaperWM.window_filter", + "desc": "Windows captured by this filter are automatically tiled and managed", + "desc_gfm": "

Windows captured by this filter are automatically tiled and managed

\n", + "doc": "Windows captured by this filter are automatically tiled and managed", + "doc_gfm": "

Windows captured by this filter are automatically tiled and managed

\n", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "150", + "name": "window_filter", + "signature": "PaperWM.window_filter", + "stripped_doc": "", + "type": "Variable" + }, + { + "def": "PaperWM.window_gap", + "def_gfm": "PaperWM.window_gap", + "desc": "Number of pixels between tiled windows", + "desc_gfm": "

Number of pixels between tiled windows

\n", + "doc": "Number of pixels between tiled windows", + "doc_gfm": "

Number of pixels between tiled windows

\n", + "file": "Source/PaperWM.spoon/init.lua", + "lineno": "160", + "name": "window_gap", + "signature": "PaperWM.window_gap", + "stripped_doc": "", + "type": "Variable" + } + ], + "name": "PaperWM", + "stripped_doc": "\n# Usage\n\n`PaperWM:start()` will begin automatically tiling new and existing windows.\n`PaperWM:stop()` will release control over windows.\n`PaperWM::bindHotkeys()` will move / resize windows using keyboard shortcuts.\n\nHere is an example Hammerspoon config:\n\n```\nPaperWM = hs.loadSpoon(\"PaperWM\")\nPaperWM:bindHotkeys({\n -- switch to a new focused window in tiled grid\n focus_left = {{\"ctrl\", \"alt\", \"cmd\"}, \"left\"},\n focus_right = {{\"ctrl\", \"alt\", \"cmd\"}, \"right\"},\n focus_up = {{\"ctrl\", \"alt\", \"cmd\"}, \"up\"},\n focus_down = {{\"ctrl\", \"alt\", \"cmd\"}, \"down\"},\n\n -- move windows around in tiled grid\n swap_left = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"left\"},\n swap_right = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"right\"},\n swap_up = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"up\"},\n swap_down = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"down\"},\n\n -- position and resize focused window\n center_window = {{\"ctrl\", \"alt\", \"cmd\"}, \"c\"},\n full_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"f\"},\n cycle_width = {{\"ctrl\", \"alt\", \"cmd\"}, \"r\"},\n cycle_height = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"r\"},\n\n -- move focused window into / out of a column\n slurp_in = {{\"ctrl\", \"alt\", \"cmd\"}, \"i\"},\n barf_out = {{\"ctrl\", \"alt\", \"cmd\"}, \"o\"},\n\n -- switch to a new Mission Control space\n switch_space_1 = {{\"ctrl\", \"alt\", \"cmd\"}, \"1\"},\n switch_space_2 = {{\"ctrl\", \"alt\", \"cmd\"}, \"2\"},\n switch_space_3 = {{\"ctrl\", \"alt\", \"cmd\"}, \"3\"},\n switch_space_4 = {{\"ctrl\", \"alt\", \"cmd\"}, \"4\"},\n switch_space_5 = {{\"ctrl\", \"alt\", \"cmd\"}, \"5\"},\n switch_space_6 = {{\"ctrl\", \"alt\", \"cmd\"}, \"6\"},\n switch_space_7 = {{\"ctrl\", \"alt\", \"cmd\"}, \"7\"},\n switch_space_8 = {{\"ctrl\", \"alt\", \"cmd\"}, \"8\"},\n switch_space_9 = {{\"ctrl\", \"alt\", \"cmd\"}, \"9\"},\n\n -- move focused window to a new space and tile\n move_window_1 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"1\"},\n move_window_2 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"2\"},\n move_window_3 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"3\"},\n move_window_4 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"4\"},\n move_window_5 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"5\"},\n move_window_6 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"6\"},\n move_window_7 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"7\"},\n move_window_8 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"8\"},\n move_window_9 = {{\"ctrl\", \"alt\", \"cmd\", \"shift\"}, \"9\"}\n})\nPaperWM:start()\n```\n\nUse `PaperWM:bindHotkeys(PaperWM.default_hotkeys)` for defaults.\n\nSet `PaperWM.window_gap` to the number of pixels to space between windows and\nthe top and bottom screen edges.\n\nOverwrite `PaperWM.window_filter` to ignore specific applications. For example:\n\n```\nPaperWM.window_filter = PaperWM.window_filter:setAppFilter(\"Finder\", false)\nPaperWM:start() -- restart for new window filter to take effect\n```\n\n# Limitations\n\nUnder System Preferences -> Mission Control, unselect \"Automatically\nrearrange Spaces based on most recent use\" and select \"Displays have separate\nSpaces\".\n\nMacOS does not allow a window to be moved fully off-screen. Windows that would\nbe tiled off-screen are placed in a margin on the left and right edge of the\nscreen. They are still visible and clickable.\n\nIt's difficult to detect when a window is dragged from one space or screen to\nanother. Use the move_window_N commands to move windows between spaces and\nscreens.\n\nArrange screens vertically to prevent windows from bleeding into other screens.\n\n\nDownload: [https://github.com/mogenson/PaperWM.spoon](https://github.com/mogenson/PaperWM.spoon)", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], From 0f80199a0d9c004e3d625312b15322be6b202f95 Mon Sep 17 00:00:00 2001 From: Lunaticsky-tql <99857443+Lunaticsky-tql@users.noreply.github.com> Date: Wed, 7 Aug 2024 21:33:27 +0800 Subject: [PATCH 44/55] Add InputMethodIndicator.spoon (#307) --- Source/InputMethodIndicator.spoon/docs.json | 177 +++++++++++++ Source/InputMethodIndicator.spoon/init.lua | 268 ++++++++++++++++++++ 2 files changed, 445 insertions(+) create mode 100644 Source/InputMethodIndicator.spoon/docs.json create mode 100644 Source/InputMethodIndicator.spoon/init.lua diff --git a/Source/InputMethodIndicator.spoon/docs.json b/Source/InputMethodIndicator.spoon/docs.json new file mode 100644 index 00000000..95484e7e --- /dev/null +++ b/Source/InputMethodIndicator.spoon/docs.json @@ -0,0 +1,177 @@ +[ + { + "Constant" : [ + + ], + "submodules" : [ + + ], + "Function" : [ + + ], + "Variable" : [ + + ], + "stripped_doc" : [ + + ], + "desc" : "Show input method indicator in the current mouse position.", + "Deprecated" : [ + + ], + "type" : "Module", + "Constructor" : [ + + ], + "Field" : [ + + ], + "Method" : [ + { + "doc" : "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", + "stripped_doc" : [ + "init.", + "" + ], + "def" : "InputMethodIndicator:init()", + "parameters" : [ + " * None", + "" + ], + "notes" : [ + + ], + "signature" : "InputMethodIndicator:init()", + "type" : "Method", + "returns" : [ + " * The InputMethodIndicator object" + ], + "desc" : "init.", + "name" : "init" + }, + { + "doc" : "Start InputMethodIndicator.\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", + "stripped_doc" : [ + "Start InputMethodIndicator." + ], + "def" : "InputMethodIndicator:start(config)", + "parameters" : [ + " * config - A table contains config options for the module", + " * ABCColor - the dot color when the input method is ABC", + " * LocalLanguageColor - the dot color when the input method is not ABC", + " * mode - the mode of the indicator", + " * showOnChangeDuration - seconds to show the indicator when the input method is changed", + " * checkInterval - seconds to check the input method", + " * dotSize - the size of the dot", + " * deltaY - the distance between the dot and the center of the selection or mouse" + ], + "notes" : [ + + ], + "signature" : "InputMethodIndicator:start(config)", + "type" : "Method", + "returns" : [ + + ], + "desc" : "Start InputMethodIndicator.", + "name" : "start" + }, + { + "doc" : "Stop InputMethodIndicator.\nParameters:\n * None", + "stripped_doc" : [ + "Stop InputMethodIndicator." + ], + "def" : "InputMethodIndicator:stop()", + "parameters" : [ + " * None" + ], + "notes" : [ + + ], + "signature" : "InputMethodIndicator:stop()", + "type" : "Method", + "returns" : [ + + ], + "desc" : "Stop InputMethodIndicator.", + "name" : "stop" + } + ], + "Command" : [ + + ], + "doc" : "Show input method indicator in the current mouse position.\nIt is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon(\"InputMethodIndicator\")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = \"#62C555\", -- the dot color when the input method is ABC\n LocalLanguageColor = \"#ED6A5E\", -- the dot color when the input method is not ABC\n mode = \"nearMouse\", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be \"nearMouse\",\"onChange\",\"adaptive\", the default mode is \"adaptive\"\n\"nearMouse\" means the indicator will always show near the mouse\n\"onChange\" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n\"adaptive\" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the \"adaptive\" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API", + "items" : [ + { + "doc" : "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", + "stripped_doc" : [ + "init.", + "" + ], + "def" : "InputMethodIndicator:init()", + "parameters" : [ + " * None", + "" + ], + "notes" : [ + + ], + "signature" : "InputMethodIndicator:init()", + "type" : "Method", + "returns" : [ + " * The InputMethodIndicator object" + ], + "desc" : "init.", + "name" : "init" + }, + { + "doc" : "Start InputMethodIndicator.\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", + "stripped_doc" : [ + "Start InputMethodIndicator." + ], + "def" : "InputMethodIndicator:start(config)", + "parameters" : [ + " * config - A table contains config options for the module", + " * ABCColor - the dot color when the input method is ABC", + " * LocalLanguageColor - the dot color when the input method is not ABC", + " * mode - the mode of the indicator", + " * showOnChangeDuration - seconds to show the indicator when the input method is changed", + " * checkInterval - seconds to check the input method", + " * dotSize - the size of the dot", + " * deltaY - the distance between the dot and the center of the selection or mouse" + ], + "notes" : [ + + ], + "signature" : "InputMethodIndicator:start(config)", + "type" : "Method", + "returns" : [ + + ], + "desc" : "Start InputMethodIndicator.", + "name" : "start" + }, + { + "doc" : "Stop InputMethodIndicator.\nParameters:\n * None", + "stripped_doc" : [ + "Stop InputMethodIndicator." + ], + "def" : "InputMethodIndicator:stop()", + "parameters" : [ + " * None" + ], + "notes" : [ + + ], + "signature" : "InputMethodIndicator:stop()", + "type" : "Method", + "returns" : [ + + ], + "desc" : "Stop InputMethodIndicator.", + "name" : "stop" + } + ], + "name" : "InputMethodIndicator" + } +] diff --git a/Source/InputMethodIndicator.spoon/init.lua b/Source/InputMethodIndicator.spoon/init.lua new file mode 100644 index 00000000..22051ec2 --- /dev/null +++ b/Source/InputMethodIndicator.spoon/init.lua @@ -0,0 +1,268 @@ +--- === InputMethodIndicator === +--- +--- Show input method indicator in the current mouse position. +--- It is a small but noticable dot near the cursor. +--- It can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method. +--- You can use it as follows in the init.lua: +--- hs.loadSpoon("InputMethodIndicator") +--- spoon.InputMethodIndicator:start(nil) +--- note: config parameter is a table, pass nil to use the default config +--- the default config is as follows: +--- { +--- ABCColor = "#62C555", -- the dot color when the input method is ABC +--- LocalLanguageColor = "#ED6A5E", -- the dot color when the input method is not ABC +--- mode = "nearMouse", -- the mode of the indicator +--- showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed +--- checkInterval = .01, -- seconds to check the input method +--- dotSize = 6, -- the size of the dot +--- deltaY=7, -- the distance between the dot and the center of the selection or mouse +--- } +--- the mode can be "nearMouse","onChange","adaptive", the default mode is "adaptive" +--- "nearMouse" means the indicator will always show near the mouse +--- "onChange" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds +--- "adaptive" means the indicator will show near the textarea when typing, otherwise it will show near the mouse +--- Note: the "adaptive" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API + +local obj = {} +local _store = {} +setmetatable(obj, { + __index = function(_, k) + return _store[k] + end, + __newindex = function(t, k, v) + rawset(_store, k, v) + if t._init_done then + if t._attribs[k] then + t:init() + end + end + end +}) +obj.__index = obj + +-- Metadata +obj.name = "InputMethodIndicator" +obj.version = "1.0" +obj.author = "lunaticsky <2013599@mail.nankai.edu.cn>" +obj.homepage = "https://github.com/Hammerspoon/Spoons" +obj.license = "MIT - https://opensource.org/licenses/MIT" + +local logger = hs.logger.new("InputMethodIndicator") +obj.logger = logger + +-- Defaults +obj._attribs = { + ABCColor = "#62C555", + LocalLanguageColor = "#ED6A5E", + mode = "adaptive", + showOnChangeDuration = 3, + checkInterval = .01, + dotSize = 6, + deltaY=7, +} +for k, v in pairs(obj._attribs) do + obj[k] = v +end + +--- InputMethodIndicator:init() +--- Method +--- init. +--- +--- Parameters: +--- * None +--- +--- Returns: +--- * The InputMethodIndicator object +function obj:init() + local mousePosition = hs.mouse.absolutePosition() + if not self.canvas then + self.canvas = hs.canvas.new({ + x = mousePosition.x - self.dotSize / 2, + y = mousePosition.y - 2*self.deltaY, + w = self.dotSize, + h = self.dotSize + }) + end + local sourceID = hs.keycodes.currentSourceID() + print(sourceID) + if (sourceID == "com.apple.keylayout.ABC") then + self.color = self.ABCColor + self.lastLayout = sourceID + else + self.color = self.LocalLanguageColor + self.lastLayout = sourceID + end + self.canvas[1] = { + action = "fill", + type = "circle", + fillColor = { + hex = self.color + }, + frame = { + x = 0, + y = 0, + h = self.dotSize, + w = self.dotSize + } + } + self._init_done = true + return self +end + +function obj:hideCanvasTimer() + return hs.timer.doAfter(self.showOnChangeDuration, function() + self.canvas:hide() + end) +end + +function obj:showCanvasOnChanged() + local sourceID = hs.keycodes.currentSourceID() + if (sourceID == self.lastLayout) then + return + end + self.setColor(self, sourceID) + self.canvas:show() + if not self.hideCanvasTimer:running() then + self.hideCanvasTimer:start() + else + self.hideCanvasTimer:stop() + self.hideCanvasTimer:start() + end +end +function obj:setColor(sourceID) + -- change the color of the circle according to the input layout + if (sourceID == "com.apple.keylayout.ABC") then + self.color = self.ABCColor + else + self.color = self.LocalLanguageColor + end + self.lastLayout = sourceID + self.canvas[1].fillColor = { + hex = self.color + } +end + +function obj:showNearMouse() + local cp = hs.mouse.absolutePosition() + -- change the position of the canvas + self.canvas:topLeft({ + x = cp.x - self.dotSize / 2, + y = cp.y - 15 + }) +end + +function obj:adaptiveChangePosition() + local systemWideElement = hs.axuielement.systemWideElement() + local focusedElement = systemWideElement.AXFocusedUIElement + if focusedElement then + local selectedRange = focusedElement.AXSelectedTextRange + if selectedRange then + local selectionBounds = focusedElement:parameterizedAttributeValue("AXBoundsForRange", selectedRange) + -- print the position and size of the selection,which is a table + if selectionBounds then + if selectionBounds.h == 0 or selectionBounds.y < 0 then + self:showNearMouse() + else + self.canvas:topLeft({ + x = selectionBounds.x - self.dotSize / 2, + y = selectionBounds.y - self.deltaY + }) + end + else + self:showNearMouse() + end + else + self:showNearMouse() + end + end +end + +function obj:adaptiveTimer() + return hs.timer.doEvery(self.checkInterval, function() + self:adaptiveChangePosition() + self:setColor(hs.keycodes.currentSourceID()) + end) +end + +function obj:showOnChangeTimer() + return hs.timer.doEvery(self.checkInterval, function() + self:adaptiveChangePosition() + self:showCanvasOnChanged() + end) +end + +function obj:showNearMouseTimer() + return hs.timer.doEvery(self.checkInterval, function() + self:showNearMouse() + self:setColor(hs.keycodes.currentSourceID()) + end) +end +--- InputMethodIndicator:start(config) +--- Method +--- Start InputMethodIndicator. +--- +--- Parameters: +--- * config - A table contains config options for the module +--- * ABCColor - the dot color when the input method is ABC +--- * LocalLanguageColor - the dot color when the input method is not ABC +--- * mode - the mode of the indicator +--- * showOnChangeDuration - seconds to show the indicator when the input method is changed +--- * checkInterval - seconds to check the input method +--- * dotSize - the size of the dot +--- * deltaY - the distance between the dot and the center of the selection or mouse +function obj:start(config) + -- check whether the config is a table + if config then + if type(config) ~= "table" then + hs.alert.show("Config must be a table") + logger.e("Config must be a table") + return + end + for k, v in pairs(config) do + if self[k] then + self[k] = v + else + logger.e("Invalid config key: " .. k) + end + end + end + if self.mode == "onChange" then + self.hideCanvasTimer = self:hideCanvasTimer() + self.showOnChangeTimer = self:showOnChangeTimer() + elseif self.mode == "adaptive" then + self.canvas:show() + self.adaptiveTimer = self:adaptiveTimer() + elseif self.mode == "nearMouse" then + self.canvas:show() + self.showNearMouseTimer = self:showNearMouseTimer() + else + hs.alert.show("Invalid mode") + logger.e("Invalid mode") + return + end +end + +--- InputMethodIndicator:stop() +--- Method +--- Stop InputMethodIndicator. +--- +--- Parameters: +--- * None +function obj:stop() + self.canvas:hide() + self.canvas = nil + if self.showOnChangeTimer then + self.showOnChangeTimer:stop() + self.showOnChangeTimer = nil + end + if self.adaptiveTimer then + self.adaptiveTimer:stop() + self.adaptiveTimer = nil + end + if self.showNearMouseTimer then + self.showNearMouseTimer:stop() + self.showNearMouseTimer=nil + end +end + +return obj From 05fa99cb12bfd81ab19640af4233b8fcaa7fcbf7 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:33:52 +0000 Subject: [PATCH 45/55] Generate docs for InputMethodIndicator --- Source/InputMethodIndicator.spoon/docs.json | 250 ++++++++------------ 1 file changed, 100 insertions(+), 150 deletions(-) diff --git a/Source/InputMethodIndicator.spoon/docs.json b/Source/InputMethodIndicator.spoon/docs.json index 95484e7e..5cab46ff 100644 --- a/Source/InputMethodIndicator.spoon/docs.json +++ b/Source/InputMethodIndicator.spoon/docs.json @@ -1,177 +1,127 @@ [ { - "Constant" : [ - - ], - "submodules" : [ - - ], - "Function" : [ - - ], - "Variable" : [ - - ], - "stripped_doc" : [ - - ], - "desc" : "Show input method indicator in the current mouse position.", - "Deprecated" : [ - - ], - "type" : "Module", - "Constructor" : [ - - ], - "Field" : [ - - ], - "Method" : [ + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ { - "doc" : "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", - "stripped_doc" : [ - "init.", - "" - ], - "def" : "InputMethodIndicator:init()", - "parameters" : [ - " * None", - "" - ], - "notes" : [ - + "def": "InputMethodIndicator:init()", + "desc": "init.", + "doc": "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", + "examples": [], + "file": "Source/InputMethodIndicator.spoon//init.lua", + "lineno": "67", + "name": "init", + "notes": [], + "parameters": [ + " * None" ], - "signature" : "InputMethodIndicator:init()", - "type" : "Method", - "returns" : [ + "returns": [ " * The InputMethodIndicator object" ], - "desc" : "init.", - "name" : "init" + "signature": "InputMethodIndicator:init()", + "stripped_doc": "", + "type": "Method" }, { - "doc" : "Start InputMethodIndicator.\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", - "stripped_doc" : [ - "Start InputMethodIndicator." - ], - "def" : "InputMethodIndicator:start(config)", - "parameters" : [ - " * config - A table contains config options for the module", - " * ABCColor - the dot color when the input method is ABC", - " * LocalLanguageColor - the dot color when the input method is not ABC", - " * mode - the mode of the indicator", - " * showOnChangeDuration - seconds to show the indicator when the input method is changed", - " * checkInterval - seconds to check the input method", - " * dotSize - the size of the dot", - " * deltaY - the distance between the dot and the center of the selection or mouse" - ], - "notes" : [ - - ], - "signature" : "InputMethodIndicator:start(config)", - "type" : "Method", - "returns" : [ - - ], - "desc" : "Start InputMethodIndicator.", - "name" : "start" + "def": "InputMethodIndicator:start(config)", + "desc": "Start InputMethodIndicator.", + "doc": "Start InputMethodIndicator.\n\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", + "examples": [], + "file": "Source/InputMethodIndicator.spoon//init.lua", + "lineno": "200", + "name": "start", + "notes": [], + "parameters": [ + " * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse" + ], + "returns": [], + "signature": "InputMethodIndicator:start(config)", + "stripped_doc": "", + "type": "Method" }, { - "doc" : "Stop InputMethodIndicator.\nParameters:\n * None", - "stripped_doc" : [ - "Stop InputMethodIndicator." - ], - "def" : "InputMethodIndicator:stop()", - "parameters" : [ + "def": "InputMethodIndicator:stop()", + "desc": "Stop InputMethodIndicator.", + "doc": "Stop InputMethodIndicator.\n\nParameters:\n * None", + "examples": [], + "file": "Source/InputMethodIndicator.spoon//init.lua", + "lineno": "245", + "name": "stop", + "notes": [], + "parameters": [ " * None" ], - "notes" : [ - - ], - "signature" : "InputMethodIndicator:stop()", - "type" : "Method", - "returns" : [ - - ], - "desc" : "Stop InputMethodIndicator.", - "name" : "stop" + "returns": [], + "signature": "InputMethodIndicator:stop()", + "stripped_doc": "", + "type": "Method" } ], - "Command" : [ - - ], - "doc" : "Show input method indicator in the current mouse position.\nIt is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon(\"InputMethodIndicator\")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = \"#62C555\", -- the dot color when the input method is ABC\n LocalLanguageColor = \"#ED6A5E\", -- the dot color when the input method is not ABC\n mode = \"nearMouse\", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be \"nearMouse\",\"onChange\",\"adaptive\", the default mode is \"adaptive\"\n\"nearMouse\" means the indicator will always show near the mouse\n\"onChange\" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n\"adaptive\" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the \"adaptive\" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API", - "items" : [ + "Variable": [], + "desc": "Show input method indicator in the current mouse position.", + "doc": "Show input method indicator in the current mouse position.\nIt is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon(\"InputMethodIndicator\")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = \"#62C555\", -- the dot color when the input method is ABC\n LocalLanguageColor = \"#ED6A5E\", -- the dot color when the input method is not ABC\n mode = \"nearMouse\", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be \"nearMouse\",\"onChange\",\"adaptive\", the default mode is \"adaptive\"\n\"nearMouse\" means the indicator will always show near the mouse\n\"onChange\" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n\"adaptive\" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the \"adaptive\" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API", + "items": [ { - "doc" : "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", - "stripped_doc" : [ - "init.", - "" - ], - "def" : "InputMethodIndicator:init()", - "parameters" : [ - " * None", - "" - ], - "notes" : [ - + "def": "InputMethodIndicator:init()", + "desc": "init.", + "doc": "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", + "examples": [], + "file": "Source/InputMethodIndicator.spoon//init.lua", + "lineno": "67", + "name": "init", + "notes": [], + "parameters": [ + " * None" ], - "signature" : "InputMethodIndicator:init()", - "type" : "Method", - "returns" : [ + "returns": [ " * The InputMethodIndicator object" ], - "desc" : "init.", - "name" : "init" + "signature": "InputMethodIndicator:init()", + "stripped_doc": "", + "type": "Method" }, { - "doc" : "Start InputMethodIndicator.\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", - "stripped_doc" : [ - "Start InputMethodIndicator." - ], - "def" : "InputMethodIndicator:start(config)", - "parameters" : [ - " * config - A table contains config options for the module", - " * ABCColor - the dot color when the input method is ABC", - " * LocalLanguageColor - the dot color when the input method is not ABC", - " * mode - the mode of the indicator", - " * showOnChangeDuration - seconds to show the indicator when the input method is changed", - " * checkInterval - seconds to check the input method", - " * dotSize - the size of the dot", - " * deltaY - the distance between the dot and the center of the selection or mouse" - ], - "notes" : [ - - ], - "signature" : "InputMethodIndicator:start(config)", - "type" : "Method", - "returns" : [ - - ], - "desc" : "Start InputMethodIndicator.", - "name" : "start" + "def": "InputMethodIndicator:start(config)", + "desc": "Start InputMethodIndicator.", + "doc": "Start InputMethodIndicator.\n\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", + "examples": [], + "file": "Source/InputMethodIndicator.spoon//init.lua", + "lineno": "200", + "name": "start", + "notes": [], + "parameters": [ + " * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse" + ], + "returns": [], + "signature": "InputMethodIndicator:start(config)", + "stripped_doc": "", + "type": "Method" }, { - "doc" : "Stop InputMethodIndicator.\nParameters:\n * None", - "stripped_doc" : [ - "Stop InputMethodIndicator." - ], - "def" : "InputMethodIndicator:stop()", - "parameters" : [ + "def": "InputMethodIndicator:stop()", + "desc": "Stop InputMethodIndicator.", + "doc": "Stop InputMethodIndicator.\n\nParameters:\n * None", + "examples": [], + "file": "Source/InputMethodIndicator.spoon//init.lua", + "lineno": "245", + "name": "stop", + "notes": [], + "parameters": [ " * None" ], - "notes" : [ - - ], - "signature" : "InputMethodIndicator:stop()", - "type" : "Method", - "returns" : [ - - ], - "desc" : "Stop InputMethodIndicator.", - "name" : "stop" + "returns": [], + "signature": "InputMethodIndicator:stop()", + "stripped_doc": "", + "type": "Method" } ], - "name" : "InputMethodIndicator" + "name": "InputMethodIndicator", + "stripped_doc": "It is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon(\"InputMethodIndicator\")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = \"#62C555\", -- the dot color when the input method is ABC\n LocalLanguageColor = \"#ED6A5E\", -- the dot color when the input method is not ABC\n mode = \"nearMouse\", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be \"nearMouse\",\"onChange\",\"adaptive\", the default mode is \"adaptive\"\n\"nearMouse\" means the indicator will always show near the mouse\n\"onChange\" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n\"adaptive\" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the \"adaptive\" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API", + "submodules": [], + "type": "Module" } -] +] \ No newline at end of file From 7d77155f19bef665db928c5f35cc68999076a9e6 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:33:52 +0000 Subject: [PATCH 46/55] Add binary package for InputMethodIndicator. --- Spoons/InputMethodIndicator.spoon.zip | Bin 0 -> 3950 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Spoons/InputMethodIndicator.spoon.zip diff --git a/Spoons/InputMethodIndicator.spoon.zip b/Spoons/InputMethodIndicator.spoon.zip new file mode 100644 index 0000000000000000000000000000000000000000..dcbf8da619f1244343906c98a35b3707601ad6d9 GIT binary patch literal 3950 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 S@7JLG)#ZNOU4;4f>i+=It`D97 literal 0 HcmV?d00001 From 8c1667eb7fa66759886a8da4356be142341269cc Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:33:53 +0000 Subject: [PATCH 47/55] Update docs --- docs/InputMethodIndicator.html | 168 +++++++++++++++++++++++++++++++++ docs/docs.json | 125 ++++++++++++++++++++++++ docs/docs_index.json | 23 +++++ docs/index.html | 5 + docs/templated_docs.json | 163 ++++++++++++++++++++++++++++++++ 5 files changed, 484 insertions(+) create mode 100644 docs/InputMethodIndicator.html diff --git a/docs/InputMethodIndicator.html b/docs/InputMethodIndicator.html new file mode 100644 index 00000000..65b25ce0 --- /dev/null +++ b/docs/InputMethodIndicator.html @@ -0,0 +1,168 @@ + + + + Hammerspoon docs: InputMethodIndicator + + + + +
+

docs » InputMethodIndicator

+

Show input method indicator in the current mouse position. +It is a small but noticable dot near the cursor. +It can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method. +You can use it as follows in the init.lua: +hs.loadSpoon("InputMethodIndicator") +spoon.InputMethodIndicator:start(nil) +note: config parameter is a table, pass nil to use the default config +the default config is as follows: +{ + ABCColor = "#62C555", -- the dot color when the input method is ABC + LocalLanguageColor = "#ED6A5E", -- the dot color when the input method is not ABC + mode = "nearMouse", -- the mode of the indicator + showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed + checkInterval = .01, -- seconds to check the input method + dotSize = 6, -- the size of the dot + deltaY=7, -- the distance between the dot and the center of the selection or mouse +} +the mode can be "nearMouse","onChange","adaptive", the default mode is "adaptive" +"nearMouse" means the indicator will always show near the mouse +"onChange" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds +"adaptive" means the indicator will show near the textarea when typing, otherwise it will show near the mouse +Note: the "adaptive" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API

+ +
+

API Overview

+
    +
  • Methods - API calls which can only be made on an object returned by a constructor
  • + +
+

API Documentation

+

Methods

+
+ +
init
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureInputMethodIndicator:init()
TypeMethod
Description

init.

+
Parameters
    +
  • None
  • +
+
Returns
    +
  • The InputMethodIndicator object
  • +
+
SourceSource/InputMethodIndicator.spoon/init.lua line 67
+
+
+ +
start
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureInputMethodIndicator:start(config)
TypeMethod
Description

Start InputMethodIndicator.

+
Parameters
    +
  • config - A table contains config options for the module
      +
    • ABCColor - the dot color when the input method is ABC
    • +
    • LocalLanguageColor - the dot color when the input method is not ABC
    • +
    • mode - the mode of the indicator
    • +
    • showOnChangeDuration - seconds to show the indicator when the input method is changed
    • +
    • checkInterval - seconds to check the input method
    • +
    • dotSize - the size of the dot
    • +
    • deltaY - the distance between the dot and the center of the selection or mouse
    • +
    +
  • +
+
Returns
SourceSource/InputMethodIndicator.spoon/init.lua line 200
+
+
+ +
stop
+ + + + + + + + + + + + + + + + + + + + + + + + + +
SignatureInputMethodIndicator:stop()
TypeMethod
Description

Stop InputMethodIndicator.

+
Parameters
    +
  • None
  • +
+
Returns
SourceSource/InputMethodIndicator.spoon/init.lua line 245
+
+ + \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index 97883891..df1f55d4 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -6782,6 +6782,131 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "InputMethodIndicator:init()", + "desc": "init.", + "doc": "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "67", + "name": "init", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The InputMethodIndicator object" + ], + "signature": "InputMethodIndicator:init()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputMethodIndicator:start(config)", + "desc": "Start InputMethodIndicator.", + "doc": "Start InputMethodIndicator.\n\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "200", + "name": "start", + "notes": [], + "parameters": [ + " * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse" + ], + "returns": [], + "signature": "InputMethodIndicator:start(config)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputMethodIndicator:stop()", + "desc": "Stop InputMethodIndicator.", + "doc": "Stop InputMethodIndicator.\n\nParameters:\n * None", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "245", + "name": "stop", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "InputMethodIndicator:stop()", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [], + "desc": "Show input method indicator in the current mouse position.", + "doc": "Show input method indicator in the current mouse position.\nIt is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon(\"InputMethodIndicator\")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = \"#62C555\", -- the dot color when the input method is ABC\n LocalLanguageColor = \"#ED6A5E\", -- the dot color when the input method is not ABC\n mode = \"nearMouse\", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be \"nearMouse\",\"onChange\",\"adaptive\", the default mode is \"adaptive\"\n\"nearMouse\" means the indicator will always show near the mouse\n\"onChange\" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n\"adaptive\" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the \"adaptive\" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API", + "items": [ + { + "def": "InputMethodIndicator:init()", + "desc": "init.", + "doc": "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "67", + "name": "init", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [ + " * The InputMethodIndicator object" + ], + "signature": "InputMethodIndicator:init()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputMethodIndicator:start(config)", + "desc": "Start InputMethodIndicator.", + "doc": "Start InputMethodIndicator.\n\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "200", + "name": "start", + "notes": [], + "parameters": [ + " * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse" + ], + "returns": [], + "signature": "InputMethodIndicator:start(config)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputMethodIndicator:stop()", + "desc": "Stop InputMethodIndicator.", + "doc": "Stop InputMethodIndicator.\n\nParameters:\n * None", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "245", + "name": "stop", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], + "signature": "InputMethodIndicator:stop()", + "stripped_doc": "", + "type": "Method" + } + ], + "name": "InputMethodIndicator", + "stripped_doc": "It is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon(\"InputMethodIndicator\")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = \"#62C555\", -- the dot color when the input method is ABC\n LocalLanguageColor = \"#ED6A5E\", -- the dot color when the input method is not ABC\n mode = \"nearMouse\", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be \"nearMouse\",\"onChange\",\"adaptive\", the default mode is \"adaptive\"\n\"nearMouse\" means the indicator will always show near the mouse\n\"onChange\" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n\"adaptive\" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the \"adaptive\" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], diff --git a/docs/docs_index.json b/docs/docs_index.json index 63d51dc1..aa839ffd 100644 --- a/docs/docs_index.json +++ b/docs/docs_index.json @@ -1290,6 +1290,29 @@ "name": "show", "type": "Method" }, + { + "desc": "Show input method indicator in the current mouse position.", + "name": "InputMethodIndicator", + "type": "Module" + }, + { + "desc": "init.", + "module": "InputMethodIndicator", + "name": "init", + "type": "Method" + }, + { + "desc": "Start InputMethodIndicator.", + "module": "InputMethodIndicator", + "name": "start", + "type": "Method" + }, + { + "desc": "Stop InputMethodIndicator.", + "module": "InputMethodIndicator", + "name": "stop", + "type": "Method" + }, { "desc": "Automatically switch the input source when switching applications.", "name": "InputSourceSwitch", diff --git a/docs/index.html b/docs/index.html index 7bee12b6..ad1daf48 100644 --- a/docs/index.html +++ b/docs/index.html @@ -242,6 +242,11 @@

API documentation

HSKeybindings

Display Keybindings registered with bindHotkeys() and Spoons

+ + + + InputMethodIndicator +

Show input method indicator in the current mouse position.

diff --git a/docs/templated_docs.json b/docs/templated_docs.json index e7ffb747..fc575e8a 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -8652,6 +8652,169 @@ "submodules": [], "type": "Module" }, + { + "Command": [], + "Constant": [], + "Constructor": [], + "Deprecated": [], + "Field": [], + "Function": [], + "Method": [ + { + "def": "InputMethodIndicator:init()", + "def_gfm": "InputMethodIndicator:init()", + "desc": "init.", + "desc_gfm": "

init.

\n", + "doc": "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", + "doc_gfm": "

init.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The InputMethodIndicator object
  • \n
\n", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "67", + "name": "init", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * The InputMethodIndicator object" + ], + "returns_gfm": "
    \n
  • The InputMethodIndicator object
  • \n
\n", + "signature": "InputMethodIndicator:init()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputMethodIndicator:start(config)", + "def_gfm": "InputMethodIndicator:start(config)", + "desc": "Start InputMethodIndicator.", + "desc_gfm": "

Start InputMethodIndicator.

\n", + "doc": "Start InputMethodIndicator.\n\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", + "doc_gfm": "

Start InputMethodIndicator.

\n

Parameters:

\n
    \n
  • config - A table contains config options for the module
      \n
    • ABCColor - the dot color when the input method is ABC
    • \n
    • LocalLanguageColor - the dot color when the input method is not ABC
    • \n
    • mode - the mode of the indicator
    • \n
    • showOnChangeDuration - seconds to show the indicator when the input method is changed
    • \n
    • checkInterval - seconds to check the input method
    • \n
    • dotSize - the size of the dot
    • \n
    • deltaY - the distance between the dot and the center of the selection or mouse
    • \n
    \n
  • \n
\n", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "200", + "name": "start", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse" + ], + "parameters_gfm": "
    \n
  • config - A table contains config options for the module
      \n
    • ABCColor - the dot color when the input method is ABC
    • \n
    • LocalLanguageColor - the dot color when the input method is not ABC
    • \n
    • mode - the mode of the indicator
    • \n
    • showOnChangeDuration - seconds to show the indicator when the input method is changed
    • \n
    • checkInterval - seconds to check the input method
    • \n
    • dotSize - the size of the dot
    • \n
    • deltaY - the distance between the dot and the center of the selection or mouse
    • \n
    \n
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "InputMethodIndicator:start(config)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputMethodIndicator:stop()", + "def_gfm": "InputMethodIndicator:stop()", + "desc": "Stop InputMethodIndicator.", + "desc_gfm": "

Stop InputMethodIndicator.

\n", + "doc": "Stop InputMethodIndicator.\n\nParameters:\n * None", + "doc_gfm": "

Stop InputMethodIndicator.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "245", + "name": "stop", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "InputMethodIndicator:stop()", + "stripped_doc": "", + "type": "Method" + } + ], + "Variable": [], + "desc": "Show input method indicator in the current mouse position.", + "desc_gfm": "

Show input method indicator in the current mouse position.

\n", + "doc": "Show input method indicator in the current mouse position.\nIt is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon(\"InputMethodIndicator\")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = \"#62C555\", -- the dot color when the input method is ABC\n LocalLanguageColor = \"#ED6A5E\", -- the dot color when the input method is not ABC\n mode = \"nearMouse\", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be \"nearMouse\",\"onChange\",\"adaptive\", the default mode is \"adaptive\"\n\"nearMouse\" means the indicator will always show near the mouse\n\"onChange\" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n\"adaptive\" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the \"adaptive\" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API", + "doc_gfm": "

Show input method indicator in the current mouse position.\nIt is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon("InputMethodIndicator")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = "#62C555", -- the dot color when the input method is ABC\n LocalLanguageColor = "#ED6A5E", -- the dot color when the input method is not ABC\n mode = "nearMouse", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be "nearMouse","onChange","adaptive", the default mode is "adaptive"\n"nearMouse" means the indicator will always show near the mouse\n"onChange" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n"adaptive" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the "adaptive" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API

\n", + "items": [ + { + "def": "InputMethodIndicator:init()", + "def_gfm": "InputMethodIndicator:init()", + "desc": "init.", + "desc_gfm": "

init.

\n", + "doc": "init.\n\nParameters:\n * None\n\nReturns:\n * The InputMethodIndicator object", + "doc_gfm": "

init.

\n

Parameters:

\n
    \n
  • None
  • \n
\n

Returns:

\n
    \n
  • The InputMethodIndicator object
  • \n
\n", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "67", + "name": "init", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [ + " * The InputMethodIndicator object" + ], + "returns_gfm": "
    \n
  • The InputMethodIndicator object
  • \n
\n", + "signature": "InputMethodIndicator:init()", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputMethodIndicator:start(config)", + "def_gfm": "InputMethodIndicator:start(config)", + "desc": "Start InputMethodIndicator.", + "desc_gfm": "

Start InputMethodIndicator.

\n", + "doc": "Start InputMethodIndicator.\n\nParameters:\n * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse", + "doc_gfm": "

Start InputMethodIndicator.

\n

Parameters:

\n
    \n
  • config - A table contains config options for the module
      \n
    • ABCColor - the dot color when the input method is ABC
    • \n
    • LocalLanguageColor - the dot color when the input method is not ABC
    • \n
    • mode - the mode of the indicator
    • \n
    • showOnChangeDuration - seconds to show the indicator when the input method is changed
    • \n
    • checkInterval - seconds to check the input method
    • \n
    • dotSize - the size of the dot
    • \n
    • deltaY - the distance between the dot and the center of the selection or mouse
    • \n
    \n
  • \n
\n", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "200", + "name": "start", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * config - A table contains config options for the module\n * ABCColor - the dot color when the input method is ABC\n * LocalLanguageColor - the dot color when the input method is not ABC\n * mode - the mode of the indicator\n * showOnChangeDuration - seconds to show the indicator when the input method is changed\n * checkInterval - seconds to check the input method\n * dotSize - the size of the dot\n * deltaY - the distance between the dot and the center of the selection or mouse" + ], + "parameters_gfm": "
    \n
  • config - A table contains config options for the module
      \n
    • ABCColor - the dot color when the input method is ABC
    • \n
    • LocalLanguageColor - the dot color when the input method is not ABC
    • \n
    • mode - the mode of the indicator
    • \n
    • showOnChangeDuration - seconds to show the indicator when the input method is changed
    • \n
    • checkInterval - seconds to check the input method
    • \n
    • dotSize - the size of the dot
    • \n
    • deltaY - the distance between the dot and the center of the selection or mouse
    • \n
    \n
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "InputMethodIndicator:start(config)", + "stripped_doc": "", + "type": "Method" + }, + { + "def": "InputMethodIndicator:stop()", + "def_gfm": "InputMethodIndicator:stop()", + "desc": "Stop InputMethodIndicator.", + "desc_gfm": "

Stop InputMethodIndicator.

\n", + "doc": "Stop InputMethodIndicator.\n\nParameters:\n * None", + "doc_gfm": "

Stop InputMethodIndicator.

\n

Parameters:

\n
    \n
  • None
  • \n
\n", + "examples": [], + "file": "Source/InputMethodIndicator.spoon/init.lua", + "lineno": "245", + "name": "stop", + "notes": [], + "notes_gfm": "", + "parameters": [ + " * None" + ], + "parameters_gfm": "
    \n
  • None
  • \n
\n", + "returns": [], + "returns_gfm": "", + "signature": "InputMethodIndicator:stop()", + "stripped_doc": "", + "type": "Method" + } + ], + "name": "InputMethodIndicator", + "stripped_doc": "It is a small but noticable dot near the cursor.\nIt can be very useful when you are using a non-ABC input method and often needs to switch between ABC and the non-ABC input method.\nYou can use it as follows in the init.lua:\nhs.loadSpoon(\"InputMethodIndicator\")\nspoon.InputMethodIndicator:start(nil)\nnote: config parameter is a table, pass nil to use the default config\nthe default config is as follows:\n{\n ABCColor = \"#62C555\", -- the dot color when the input method is ABC\n LocalLanguageColor = \"#ED6A5E\", -- the dot color when the input method is not ABC\n mode = \"nearMouse\", -- the mode of the indicator\n showOnChangeDuration = 3, -- seconds to show the indicator when the input method is changed\n checkInterval = .01, -- seconds to check the input method\n dotSize = 6, -- the size of the dot\n deltaY=7, -- the distance between the dot and the center of the selection or mouse\n}\nthe mode can be \"nearMouse\",\"onChange\",\"adaptive\", the default mode is \"adaptive\"\n\"nearMouse\" means the indicator will always show near the mouse\n\"onChange\" means the indicator will show when the input method is changed and hide after showOnChangeDuration seconds\n\"adaptive\" means the indicator will show near the textarea when typing, otherwise it will show near the mouse\nNote: the \"adaptive\" mode is not perfect, it may not work in some apps because of the limitation of the accessibility API", + "submodules": [], + "type": "Module" + }, { "Command": [], "Constant": [], From 9256098fe4f6fb10f1f81f5d6aeff28877dd0a5e Mon Sep 17 00:00:00 2001 From: Mathis Koblin Date: Wed, 7 Aug 2024 15:34:24 +0200 Subject: [PATCH 48/55] Added options to enabled/disable the behaviour when a window moved or the screen changes (#308) --- Source/MouseFollowsFocus.spoon/docs.json | 6 +++--- Source/MouseFollowsFocus.spoon/init.lua | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Source/MouseFollowsFocus.spoon/docs.json b/Source/MouseFollowsFocus.spoon/docs.json index 17cb2c98..2896df1b 100644 --- a/Source/MouseFollowsFocus.spoon/docs.json +++ b/Source/MouseFollowsFocus.spoon/docs.json @@ -65,11 +65,11 @@ "items": [ { "def": "MouseFollowsFocus:configure(configuration)", - "desc": "Configures the spoon. There is currently nothing to configure.", - "doc": "Configures the spoon. There is currently nothing to configure.\n\nParameters:\n * configuration - :", + "desc": "Configures the spoon.", + "doc": "Configures the spoon.\n\nParameters:\n * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:", "name": "configure", "parameters": [ - " * configuration - :" + " * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:" ], "signature": "MouseFollowsFocus:configure(configuration)", "stripped_doc": "", diff --git a/Source/MouseFollowsFocus.spoon/init.lua b/Source/MouseFollowsFocus.spoon/init.lua index 854c441e..a6646483 100644 --- a/Source/MouseFollowsFocus.spoon/init.lua +++ b/Source/MouseFollowsFocus.spoon/init.lua @@ -17,6 +17,9 @@ obj.version = "0.1" obj.author = "Jason Felice " obj.homepage = "https://github.com/Hammerspoon/Spoons" obj.license = "MIT - https://opensource.org/licenses/MIT" +obj.onChangeOfScreenOnly = false +obj.onWindowMoved = false +obj.currentWindowScreen = nil --- MouseFollowsFocus.logger --- Variable @@ -25,11 +28,17 @@ obj.logger = hs.logger.new('MouseFollowsFocus') --- MouseFollowsFocus:configure(configuration) --- Method ---- Configures the spoon. There is currently nothing to configure. +--- Configures the spoon. --- --- Parameters: ---- * configuration - : +--- * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly: function obj:configure(configuration) + if configuration['onChangeOfScreenOnly'] then + self.onChangeOfScreenOnly = configuration['onChangeOfScreenOnly'] + end + if configuration['onWindowMoved'] then + self.onWindowMoved = configuration['onWindowMoved'] + end end --- MouseFollowsFocus:start() @@ -46,12 +55,15 @@ function obj:start() }) self.window_filter:subscribe({ hs.window.filter.windowFocused - }, function(window) - self:updateMouse(window) + }, function(window) + if self.onChangeOfScreenOnly and self.currentWindowScreen and self.currentWindowScreen:id() == window:screen():id() then return end + self:updateMouse(window) + self.currentWindowScreen = window:screen() end) self.window_filter:subscribe({ hs.window.filter.windowMoved }, function(window) + if not self.onWindowMoved then return end if window ~= hs.window.focusedWindow() then return end if #hs.mouse.getButtons() ~= 0 then return end self:updateMouse(window) From e3ddd10b99b41dd258c9c375944bba444018077e Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:34:47 +0000 Subject: [PATCH 49/55] Generate docs for MouseFollowsFocus --- Source/MouseFollowsFocus.spoon/docs.json | 92 +++++++++++++++++++----- 1 file changed, 75 insertions(+), 17 deletions(-) diff --git a/Source/MouseFollowsFocus.spoon/docs.json b/Source/MouseFollowsFocus.spoon/docs.json index 2896df1b..bdb2f014 100644 --- a/Source/MouseFollowsFocus.spoon/docs.json +++ b/Source/MouseFollowsFocus.spoon/docs.json @@ -9,12 +9,17 @@ "Method": [ { "def": "MouseFollowsFocus:configure(configuration)", - "desc": "Configures the spoon. There is currently nothing to configure.", - "doc": "Configures the spoon. There is currently nothing to configure.\n\nParameters:\n * configuration - :", + "desc": "Configures the spoon.", + "doc": "Configures the spoon.\n\nParameters:\n * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:", + "examples": [], + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "29", "name": "configure", + "notes": [], "parameters": [ - " * configuration - :" + " * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:" ], + "returns": [], "signature": "MouseFollowsFocus:configure(configuration)", "stripped_doc": "", "type": "Method" @@ -22,9 +27,16 @@ { "def": "MouseFollowsFocus:start()", "desc": "Starts updating the mouse position when window focus changes", - "doc": "Starts updating the mouse position when window focus changes\n\nParameters:", + "doc": "Starts updating the mouse position when window focus changes\n\nParameters:\n * None", + "examples": [], + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "44", "name": "start", - "parameters": [], + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], "signature": "MouseFollowsFocus:start()", "stripped_doc": "", "type": "Method" @@ -32,9 +44,16 @@ { "def": "MouseFollowsFocus:stop()", "desc": "Stops updating the mouse position when window focus changes", - "doc": "Stops updating the mouse position when window focus changes\n\nParameters:", + "doc": "Stops updating the mouse position when window focus changes\n\nParameters:\n * None", + "examples": [], + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "73", "name": "stop", - "parameters": [], + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], "signature": "MouseFollowsFocus:stop()", "stripped_doc": "", "type": "Method" @@ -42,8 +61,16 @@ { "def": "MouseFollowsFocus:updateMouse(window)", "desc": "Moves the mouse to the center of the given window unless it's already inside the window", - "doc": "Moves the mouse to the center of the given window unless it's already inside the window", + "doc": "Moves the mouse to the center of the given window unless it's already inside the window\n\nParameters:\n * None", + "examples": [], + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "84", "name": "updateMouse", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], "signature": "MouseFollowsFocus:updateMouse(window)", "stripped_doc": "", "type": "Method" @@ -54,6 +81,8 @@ "def": "MouseFollowsFocus.logger", "desc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", "doc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "24", "name": "logger", "signature": "MouseFollowsFocus.logger", "stripped_doc": "", @@ -61,16 +90,21 @@ } ], "desc": "Set the mouse pointer to the center of the focused window whenever focus changes.", - "doc": "Set the mouse pointer to the center of the focused window whenever focus changes.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MouseFollowsFocus.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MouseFollowsFocus.spoon.zip)", + "doc": "Set the mouse pointer to the center of the focused window whenever focus changes.\n\nAdditionally, if focused window moves when no mouse buttons are pressed, set the\nmouse pointer to the new center. This is intended to work with other utilities\nwhich warp the focused window.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MouseFollowsFocus.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MouseFollowsFocus.spoon.zip)", "items": [ { "def": "MouseFollowsFocus:configure(configuration)", "desc": "Configures the spoon.", - "doc": "Configures the spoon.\n\nParameters:\n * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:", + "doc": "Configures the spoon.\n\nParameters:\n * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:", + "examples": [], + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "29", "name": "configure", + "notes": [], "parameters": [ - " * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:" + " * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:" ], + "returns": [], "signature": "MouseFollowsFocus:configure(configuration)", "stripped_doc": "", "type": "Method" @@ -79,6 +113,8 @@ "def": "MouseFollowsFocus.logger", "desc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", "doc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "24", "name": "logger", "signature": "MouseFollowsFocus.logger", "stripped_doc": "", @@ -87,9 +123,16 @@ { "def": "MouseFollowsFocus:start()", "desc": "Starts updating the mouse position when window focus changes", - "doc": "Starts updating the mouse position when window focus changes\n\nParameters:", + "doc": "Starts updating the mouse position when window focus changes\n\nParameters:\n * None", + "examples": [], + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "44", "name": "start", - "parameters": [], + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], "signature": "MouseFollowsFocus:start()", "stripped_doc": "", "type": "Method" @@ -97,9 +140,16 @@ { "def": "MouseFollowsFocus:stop()", "desc": "Stops updating the mouse position when window focus changes", - "doc": "Stops updating the mouse position when window focus changes\n\nParameters:", + "doc": "Stops updating the mouse position when window focus changes\n\nParameters:\n * None", + "examples": [], + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "73", "name": "stop", - "parameters": [], + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], "signature": "MouseFollowsFocus:stop()", "stripped_doc": "", "type": "Method" @@ -107,15 +157,23 @@ { "def": "MouseFollowsFocus:updateMouse(window)", "desc": "Moves the mouse to the center of the given window unless it's already inside the window", - "doc": "Moves the mouse to the center of the given window unless it's already inside the window", + "doc": "Moves the mouse to the center of the given window unless it's already inside the window\n\nParameters:\n * None", + "examples": [], + "file": "Source/MouseFollowsFocus.spoon//init.lua", + "lineno": "84", "name": "updateMouse", + "notes": [], + "parameters": [ + " * None" + ], + "returns": [], "signature": "MouseFollowsFocus:updateMouse(window)", "stripped_doc": "", "type": "Method" } ], "name": "MouseFollowsFocus", - "stripped_doc": "\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MouseFollowsFocus.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MouseFollowsFocus.spoon.zip)", + "stripped_doc": "\nAdditionally, if focused window moves when no mouse buttons are pressed, set the\nmouse pointer to the new center. This is intended to work with other utilities\nwhich warp the focused window.\n\nDownload: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MouseFollowsFocus.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/MouseFollowsFocus.spoon.zip)", "submodules": [], "type": "Module" } From e953c21dc6f1b63e6cda5c664e7b0c3485d889c0 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:34:47 +0000 Subject: [PATCH 50/55] Add binary package for MouseFollowsFocus. --- Spoons/MouseFollowsFocus.spoon.zip | Bin 2008 -> 2475 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Spoons/MouseFollowsFocus.spoon.zip b/Spoons/MouseFollowsFocus.spoon.zip index 05c872cb86ddbbceea05b35d07753ae77e6e7d33..8903c1159ebd9f589fa13931f2eae6543d3e536d 100644 GIT binary patch literal 2475 zcmaKuXH-+!8io^!bOK5OC^Z9O1Vcvz8D$tl4ZVwKsD_dV0Z~8*D4hr7SF7N0)xs}b2_?wR05bqhvH+<8iSG{$6gpM^f z5ZYfkfQ2GMnssziqxPp<(YMzy-elo)i;%7>pV+0MwsAGhiGH={Dlj;Loj+dST2*u| zX?a4Z3`N&IMnn4IERxH0u1gKRoj}sHw$jzNnj5Ld@}nvT4al&#U|rtr7X~d*FNpEo z#z!OoWW*+W)3ub_Xu5{G+aB!d^W|unSOj>PtvO)CRNqiz^t`s!T+{6ngU7`i#CGED z;qeUAzPzWlA>EuKJZA>(^H%5xt999GqeYNEgmM>Y_i7eYU#77k@6_9fK1we4+FRUu z6-cv)%!lt(4o|C!#z%smr=?mi^}V#A28oEKTRmDcbZ(Q38TO8hubk?Xs&&AF90WpC z3x#3T@@w~^^r>tL%0f3VsP2e<&LfA?)<_PK%XHC&>EQ0)SL}Fy&NykUReJZ?pg0+- zTvOx|dCDBq##DFgQwCw$e2Xio0`D_2bliC!Uau(PRByqHIyx0 zuuM_)1QgK2ixsmmmUQc@O4VOahg1XR}eq58s zSs)$LWKuaH*L>IUb)pE#;}A(<&%(Z8&4|Ug4Bm=pC;b=9kXeY)NX@ccf38_dAs z+^iSmL*eT4(sjrbXSy#NEv3%ROg~BwOCai(&)0D>GuQ0xA!mZD77dIO@!kdWQ_9an zcHX>4XT_d98a@6q_|@3+G4>1}%wsX>-N`5kJz|;gyP{-lDJozyOK<}TSl3*2>4Boi zgQ(d)HmXZ&$ZtKe7bGV{Xlw!gt(84d9dK>3^4ZnOrW61m{~fJ(VLfqhKO7eGUt|3r zuPkKQ?0E%0xvDH2<>E-u=?Blx)k6)d5{jf#^RJo2#*nCxLPSZG66=S>6@`Ps$8rF7H@8*yx~9 zPU(6r%okK(@y>ELZj%q6mHxzv5)UzKIfOM!nt%2omLVB{x3gs?3hxT>;PK#TK;n@1KNIH3%lyu5*1`j#HDxWm56?D(#!AgwNvoC@e|K zut-gtXZP*Y6)fEXxAbxp6)?svn?nZ z(Q5T!Me=aP9959-eO;;Aj%Tk)%Q1H+c;o2d(TsO&tv}C5{$Kg{u?FK$7XY`>yezB0ZuOBtG?5MvQcWo2*nAask>Y z$XMdf!I%+^nEnchT_1}AG$-3|BX)N#Y?=W8t)}a;c(NQ{rz1lh}Zfy?akm3AR){yusb%+2K4EM@!ClBtg z$>U$y;4A%Gx#KGxxXUe!vHcGH?-a7zWiN$%r_29p=$~CmxW0Xde@N+Dm*L*G_Y*jG NU*+9X`|ZpOcecUhI~iTw1JGT#%oirym-^$-pc- z&o2RlODnh;7+GF2Gcd4J0`&#}O%!2ZV&DLqn678Cbs-Z2LxczegCZUiQ}UCG^|Ffd z^Y9t{cE-WHTMhzk?`@8rn0`sC)jC}1it|LRrLR;MWNl=x)~-(9x|{8y*86)mP0M@> zf}9p+X~_#6wSHW`=l^!O{vvyZ9|!FjE>7ukTA?!Qz~4{H;)1SmKJB~aBWZ2)_G$DL zw&aH&91_$F?PD}T->9toc1tGKO;J1MI=@H~=Q>M)vn#h)EVfy`c5YzIEl-~;-OHCA zZ20G0ad-Pg-`{D{zjrS$UB^0IF~WC=8^e5K6OKzxF;dN^o>~VyFh?@WOTacQUp#@0yr3Q$p$PF5hFDRFhIywR}F6 z{`>56r>x$S*Y|qAopJl6*UqNB{5E&?Fj&gFK5m=a^1kMT(@Nnwt@mcmntK>BHW}sA z%vStANo%3*n!R#IW(H{9;@eZN^t~fj{K$rh%Nh4Ic(tpBw>$jOWLu)&`51Ja{n3_b<>NR`;^$UZ1*KYm(qQqr?;TxW~=CJoY`#6-3Y8{_myWh=nspc%b5_xBq zjIX@O>^1R+rv2#mD0sf^*A<`ECefyjb#i(XU%QucrO@@&kDdWsmZ9-K}dc4W9IHN4ea;3v-%^ zAO85g?`YVJ!^=Y7?|4~1{o41~kJGkksZab6cy`X^G9$U=J)2{CXB_&`tikoJ;okqk z1qsL9a*nrdh*=Y7S+-NEZlCvFnK;KSb>Ye{H*EMj;Rb(aZTw&VUs?9Qzi+Mw5&vJ$ z{rkGzS}TTMx1W2@JHa#4RyR$W#JTN%?R5!Jr+X{f4}MZdr2RR-+~gy;xc)sb?cZQ$ zU{Ju5_A~P`OZ0L|6TwMe9DA4?>P)t`7?qZCn&2%E@`fJJeOW zI!8b1ebjG-r5*q8-MlF==~!mzXoh`GJo-D`kCoz zi>C^PGTx7RUmbqtdGD9pi04aRKAZ1yePQWd!>T&z`rSK4XIHArgvyw(uYE2v;s2Ds z-{07)%=J?{HN~kh^1lAOdFo%(_d0vzVOh}*0jX;oi*zo!@+-}}y=ncSD3+&D8oldMg>}*nPyeuGduEY)RK(Hw;?46Ps|gh| zyo=hxF=-diwM!RQxL;6vl&^GZ`jhp?3zc;Q+aq3bO=G-wATBj3#BgP^UZld5WsXHBkhGuJ#m_&!V{ zXtCsPpXB{j3u3gMx_NCZo~O3yX^_+|S9u-fIe(Y}ycwC~m~mB163{A2fZ?qph>5$J zVue&w7*!O=bX=7b#B@fWxl0;BH6kw4k*X}h)?k(g$kzA)D^Fb3AW8?IEuhi?!!xXG Ppg>>-LT#X{r-OL_ER9l< From ad65c7d42a2343a5afa87fe93d4b6ce2908ba8c4 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 13:34:47 +0000 Subject: [PATCH 51/55] Update docs --- docs/MouseFollowsFocus.html | 14 ++++++------ docs/docs.json | 32 +++++++++++++-------------- docs/docs_index.json | 2 +- docs/templated_docs.json | 44 ++++++++++++++++++------------------- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/docs/MouseFollowsFocus.html b/docs/MouseFollowsFocus.html index ddd545f7..cbfc13ec 100644 --- a/docs/MouseFollowsFocus.html +++ b/docs/MouseFollowsFocus.html @@ -57,7 +57,7 @@
logger
Source - Source/MouseFollowsFocus.spoon/init.lua line 21 + Source/MouseFollowsFocus.spoon/init.lua line 24 @@ -76,13 +76,13 @@
configure
Description -

Configures the spoon. There is currently nothing to configure.

+

Configures the spoon.

Parameters
    -
  • configuration - :
  • +
  • configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:
@@ -92,7 +92,7 @@
configure
Source - Source/MouseFollowsFocus.spoon/init.lua line 26 + Source/MouseFollowsFocus.spoon/init.lua line 29 @@ -126,7 +126,7 @@
start
Source - Source/MouseFollowsFocus.spoon/init.lua line 35 + Source/MouseFollowsFocus.spoon/init.lua line 44 @@ -160,7 +160,7 @@
stop
Source - Source/MouseFollowsFocus.spoon/init.lua line 61 + Source/MouseFollowsFocus.spoon/init.lua line 73 @@ -194,7 +194,7 @@
updateMouse
Source - Source/MouseFollowsFocus.spoon/init.lua line 72 + Source/MouseFollowsFocus.spoon/init.lua line 84 diff --git a/docs/docs.json b/docs/docs.json index df1f55d4..cbf7a926 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -9663,15 +9663,15 @@ "Method": [ { "def": "MouseFollowsFocus:configure(configuration)", - "desc": "Configures the spoon. There is currently nothing to configure.", - "doc": "Configures the spoon. There is currently nothing to configure.\n\nParameters:\n * configuration - :", + "desc": "Configures the spoon.", + "doc": "Configures the spoon.\n\nParameters:\n * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "26", + "lineno": "29", "name": "configure", "notes": [], "parameters": [ - " * configuration - :" + " * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:" ], "returns": [], "signature": "MouseFollowsFocus:configure(configuration)", @@ -9684,7 +9684,7 @@ "doc": "Starts updating the mouse position when window focus changes\n\nParameters:\n * None", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "35", + "lineno": "44", "name": "start", "notes": [], "parameters": [ @@ -9701,7 +9701,7 @@ "doc": "Stops updating the mouse position when window focus changes\n\nParameters:\n * None", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "61", + "lineno": "73", "name": "stop", "notes": [], "parameters": [ @@ -9718,7 +9718,7 @@ "doc": "Moves the mouse to the center of the given window unless it's already inside the window\n\nParameters:\n * None", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "72", + "lineno": "84", "name": "updateMouse", "notes": [], "parameters": [ @@ -9736,7 +9736,7 @@ "desc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", "doc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "21", + "lineno": "24", "name": "logger", "signature": "MouseFollowsFocus.logger", "stripped_doc": "", @@ -9748,15 +9748,15 @@ "items": [ { "def": "MouseFollowsFocus:configure(configuration)", - "desc": "Configures the spoon. There is currently nothing to configure.", - "doc": "Configures the spoon. There is currently nothing to configure.\n\nParameters:\n * configuration - :", + "desc": "Configures the spoon.", + "doc": "Configures the spoon.\n\nParameters:\n * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "26", + "lineno": "29", "name": "configure", "notes": [], "parameters": [ - " * configuration - :" + " * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:" ], "returns": [], "signature": "MouseFollowsFocus:configure(configuration)", @@ -9768,7 +9768,7 @@ "desc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", "doc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "21", + "lineno": "24", "name": "logger", "signature": "MouseFollowsFocus.logger", "stripped_doc": "", @@ -9780,7 +9780,7 @@ "doc": "Starts updating the mouse position when window focus changes\n\nParameters:\n * None", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "35", + "lineno": "44", "name": "start", "notes": [], "parameters": [ @@ -9797,7 +9797,7 @@ "doc": "Stops updating the mouse position when window focus changes\n\nParameters:\n * None", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "61", + "lineno": "73", "name": "stop", "notes": [], "parameters": [ @@ -9814,7 +9814,7 @@ "doc": "Moves the mouse to the center of the given window unless it's already inside the window\n\nParameters:\n * None", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "72", + "lineno": "84", "name": "updateMouse", "notes": [], "parameters": [ diff --git a/docs/docs_index.json b/docs/docs_index.json index aa839ffd..cd5edcf7 100644 --- a/docs/docs_index.json +++ b/docs/docs_index.json @@ -1834,7 +1834,7 @@ "type": "Variable" }, { - "desc": "Configures the spoon. There is currently nothing to configure.", + "desc": "Configures the spoon.", "module": "MouseFollowsFocus", "name": "configure", "type": "Method" diff --git a/docs/templated_docs.json b/docs/templated_docs.json index fc575e8a..9a5db9e1 100644 --- a/docs/templated_docs.json +++ b/docs/templated_docs.json @@ -12318,20 +12318,20 @@ { "def": "MouseFollowsFocus:configure(configuration)", "def_gfm": "MouseFollowsFocus:configure(configuration)", - "desc": "Configures the spoon. There is currently nothing to configure.", - "desc_gfm": "

Configures the spoon. There is currently nothing to configure.

\n", - "doc": "Configures the spoon. There is currently nothing to configure.\n\nParameters:\n * configuration - :", - "doc_gfm": "

Configures the spoon. There is currently nothing to configure.

\n

Parameters:

\n
    \n
  • configuration - :
  • \n
\n", + "desc": "Configures the spoon.", + "desc_gfm": "

Configures the spoon.

\n", + "doc": "Configures the spoon.\n\nParameters:\n * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:", + "doc_gfm": "

Configures the spoon.

\n

Parameters:

\n
    \n
  • configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:
  • \n
\n", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "26", + "lineno": "29", "name": "configure", "notes": [], "notes_gfm": "", "parameters": [ - " * configuration - :" + " * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:" ], - "parameters_gfm": "
    \n
  • configuration - :
  • \n
\n", + "parameters_gfm": "
    \n
  • configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:
  • \n
\n", "returns": [], "returns_gfm": "", "signature": "MouseFollowsFocus:configure(configuration)", @@ -12347,7 +12347,7 @@ "doc_gfm": "

Starts updating the mouse position when window focus changes

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "35", + "lineno": "44", "name": "start", "notes": [], "notes_gfm": "", @@ -12370,7 +12370,7 @@ "doc_gfm": "

Stops updating the mouse position when window focus changes

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "61", + "lineno": "73", "name": "stop", "notes": [], "notes_gfm": "", @@ -12393,7 +12393,7 @@ "doc_gfm": "

Moves the mouse to the center of the given window unless it's already inside the window

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "72", + "lineno": "84", "name": "updateMouse", "notes": [], "notes_gfm": "", @@ -12417,7 +12417,7 @@ "doc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", "doc_gfm": "

Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.

\n", "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "21", + "lineno": "24", "name": "logger", "signature": "MouseFollowsFocus.logger", "stripped_doc": "", @@ -12432,20 +12432,20 @@ { "def": "MouseFollowsFocus:configure(configuration)", "def_gfm": "MouseFollowsFocus:configure(configuration)", - "desc": "Configures the spoon. There is currently nothing to configure.", - "desc_gfm": "

Configures the spoon. There is currently nothing to configure.

\n", - "doc": "Configures the spoon. There is currently nothing to configure.\n\nParameters:\n * configuration - :", - "doc_gfm": "

Configures the spoon. There is currently nothing to configure.

\n

Parameters:

\n
    \n
  • configuration - :
  • \n
\n", + "desc": "Configures the spoon.", + "desc_gfm": "

Configures the spoon.

\n", + "doc": "Configures the spoon.\n\nParameters:\n * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:", + "doc_gfm": "

Configures the spoon.

\n

Parameters:

\n
    \n
  • configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:
  • \n
\n", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "26", + "lineno": "29", "name": "configure", "notes": [], "notes_gfm": "", "parameters": [ - " * configuration - :" + " * configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:" ], - "parameters_gfm": "
    \n
  • configuration - :
  • \n
\n", + "parameters_gfm": "
    \n
  • configuration - a table containing the settings for onWindowMoved or onChangeOfScreenOnly:
  • \n
\n", "returns": [], "returns_gfm": "", "signature": "MouseFollowsFocus:configure(configuration)", @@ -12460,7 +12460,7 @@ "doc": "Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.", "doc_gfm": "

Logger object used within the Spoon. Can be accessed to set the default log level for the messages coming from the Spoon.

\n", "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "21", + "lineno": "24", "name": "logger", "signature": "MouseFollowsFocus.logger", "stripped_doc": "", @@ -12475,7 +12475,7 @@ "doc_gfm": "

Starts updating the mouse position when window focus changes

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "35", + "lineno": "44", "name": "start", "notes": [], "notes_gfm": "", @@ -12498,7 +12498,7 @@ "doc_gfm": "

Stops updating the mouse position when window focus changes

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "61", + "lineno": "73", "name": "stop", "notes": [], "notes_gfm": "", @@ -12521,7 +12521,7 @@ "doc_gfm": "

Moves the mouse to the center of the given window unless it's already inside the window

\n

Parameters:

\n
    \n
  • None
  • \n
\n", "examples": [], "file": "Source/MouseFollowsFocus.spoon/init.lua", - "lineno": "72", + "lineno": "84", "name": "updateMouse", "notes": [], "notes_gfm": "", From 9975235f81dc79f5ba6e1297922a420446f2a670 Mon Sep 17 00:00:00 2001 From: andrewcrook <803618+andrewcrook@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:14:12 +0100 Subject: [PATCH 52/55] Fixed Keychain addItem (#312) --- Source/Keychain.spoon/init.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Keychain.spoon/init.lua b/Source/Keychain.spoon/init.lua index 963c5006..afdf2759 100644 --- a/Source/Keychain.spoon/init.lua +++ b/Source/Keychain.spoon/init.lua @@ -150,7 +150,7 @@ end --- * comment - comment --- * label - label (defaults to service name) --- * service - service name (required) -function obj:addPassword(options) +function obj:addItem(options) local cmd="/usr/bin/security add-generic-password" @@ -160,7 +160,6 @@ function obj:addPassword(options) end end - cmd = cmd .. "-w " .. options.password local handle = io.popen(cmd) local result = handle:read("*a") From 548c9ceb7eaf0caac158b2093931385ce31842e6 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 14:14:34 +0000 Subject: [PATCH 53/55] Generate docs for Keychain --- Source/Keychain.spoon/docs.json | 48 ++++++++++----------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/Source/Keychain.spoon/docs.json b/Source/Keychain.spoon/docs.json index 3ff47d7a..f25b9339 100644 --- a/Source/Keychain.spoon/docs.json +++ b/Source/Keychain.spoon/docs.json @@ -29,20 +29,15 @@ "def": "Keychain:addItem(options)", "desc": "Add generic password to keychain.", "doc": "Add generic password to keychain.\n\nParameters:\n * options is a table with values for what keys to try locate with.\n * password - the password\n * account - account name (required)\n * creator - creator, must be 4 characters\n * type - type, must be 4 characters\n * kind - kind of item\n * comment - comment \n * label - label (defaults to service name)\n * service - service name (required)", + "examples": [], "file": "Source/Keychain.spoon//init.lua", "lineno": "139", "name": "addItem", + "notes": [], "parameters": [ - " * options is a table with values for what keys to try locate with.", - " * password - the password", - " * account - account name (required)", - " * creator - creator, must be 4 characters", - " * type - type, must be 4 characters", - " * kind - kind of item", - " * comment - comment ", - " * label - label (defaults to service name)", - " * service - service name (required)" + " * options is a table with values for what keys to try locate with.\n * password - the password\n * account - account name (required)\n * creator - creator, must be 4 characters\n * type - type, must be 4 characters\n * kind - kind of item\n * comment - comment\n * label - label (defaults to service name)\n * service - service name (required)" ], + "returns": [], "signature": "Keychain:addItem(options)", "stripped_doc": "", "type": "Method" @@ -51,6 +46,7 @@ "def": "Keychain:getItem(options)", "desc": "Retrieve an item from the Login Keychain. Return nil if not found and otherwise a table with found data.", "doc": "Retrieve an item from the Login Keychain. Return nil if not found and otherwise a table with found data.\n\nParameters:\n * options is a table with values for what keys to try locate with.\n * account - account name\n * creator - creator, must be 4 characters\n * type - type, must be 4 characters\n * kind - kind of item\n * comment - comment \n * label - label (defaults to service name)\n * service - service name\n\nNotes:\n * If multiple possibles matches just the first one is found.", + "examples": [], "file": "Source/Keychain.spoon//init.lua", "lineno": "82", "name": "getItem", @@ -58,15 +54,9 @@ " * If multiple possibles matches just the first one is found." ], "parameters": [ - " * options is a table with values for what keys to try locate with.", - " * account - account name", - " * creator - creator, must be 4 characters", - " * type - type, must be 4 characters", - " * kind - kind of item", - " * comment - comment ", - " * label - label (defaults to service name)", - " * service - service name" + " * options is a table with values for what keys to try locate with.\n * account - account name\n * creator - creator, must be 4 characters\n * type - type, must be 4 characters\n * kind - kind of item\n * comment - comment\n * label - label (defaults to service name)\n * service - service name" ], + "returns": [], "signature": "Keychain:getItem(options)", "stripped_doc": "", "type": "Method" @@ -92,20 +82,15 @@ "def": "Keychain:addItem(options)", "desc": "Add generic password to keychain.", "doc": "Add generic password to keychain.\n\nParameters:\n * options is a table with values for what keys to try locate with.\n * password - the password\n * account - account name (required)\n * creator - creator, must be 4 characters\n * type - type, must be 4 characters\n * kind - kind of item\n * comment - comment \n * label - label (defaults to service name)\n * service - service name (required)", + "examples": [], "file": "Source/Keychain.spoon//init.lua", "lineno": "139", "name": "addItem", + "notes": [], "parameters": [ - " * options is a table with values for what keys to try locate with.", - " * password - the password", - " * account - account name (required)", - " * creator - creator, must be 4 characters", - " * type - type, must be 4 characters", - " * kind - kind of item", - " * comment - comment ", - " * label - label (defaults to service name)", - " * service - service name (required)" + " * options is a table with values for what keys to try locate with.\n * password - the password\n * account - account name (required)\n * creator - creator, must be 4 characters\n * type - type, must be 4 characters\n * kind - kind of item\n * comment - comment\n * label - label (defaults to service name)\n * service - service name (required)" ], + "returns": [], "signature": "Keychain:addItem(options)", "stripped_doc": "", "type": "Method" @@ -114,6 +99,7 @@ "def": "Keychain:getItem(options)", "desc": "Retrieve an item from the Login Keychain. Return nil if not found and otherwise a table with found data.", "doc": "Retrieve an item from the Login Keychain. Return nil if not found and otherwise a table with found data.\n\nParameters:\n * options is a table with values for what keys to try locate with.\n * account - account name\n * creator - creator, must be 4 characters\n * type - type, must be 4 characters\n * kind - kind of item\n * comment - comment \n * label - label (defaults to service name)\n * service - service name\n\nNotes:\n * If multiple possibles matches just the first one is found.", + "examples": [], "file": "Source/Keychain.spoon//init.lua", "lineno": "82", "name": "getItem", @@ -121,15 +107,9 @@ " * If multiple possibles matches just the first one is found." ], "parameters": [ - " * options is a table with values for what keys to try locate with.", - " * account - account name", - " * creator - creator, must be 4 characters", - " * type - type, must be 4 characters", - " * kind - kind of item", - " * comment - comment ", - " * label - label (defaults to service name)", - " * service - service name" + " * options is a table with values for what keys to try locate with.\n * account - account name\n * creator - creator, must be 4 characters\n * type - type, must be 4 characters\n * kind - kind of item\n * comment - comment\n * label - label (defaults to service name)\n * service - service name" ], + "returns": [], "signature": "Keychain:getItem(options)", "stripped_doc": "", "type": "Method" From e69dfc8ec6bbffb36b9f68f6c55dda75573810c6 Mon Sep 17 00:00:00 2001 From: Spoons GitHub Bot Date: Wed, 7 Aug 2024 14:14:34 +0000 Subject: [PATCH 54/55] Add binary package for Keychain. --- Spoons/Keychain.spoon.zip | Bin 3226 -> 3206 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Spoons/Keychain.spoon.zip b/Spoons/Keychain.spoon.zip index 34360fd9d337ab9b86db447ed873e4a8544224d9..b274a60a0c3dd5aeec6498d93b81c308edda25e0 100644 GIT binary patch literal 3206 zcmaKucQhPW8;56f89|f`q9+)=Z3H1P`j|?b?)kF2x1D?cc%SqBb$^dGoRsVW;Cu|ZQ=0sK`SYLyumj+BkB|=5 zC>JqLH&<5|aRYs70I61Jt^N7-_5%TcWJFQ`fGqf|MEeZH1Rw!W0Y038jB)fg*eC#i zLwW!J{4)sUg7Ol3=xzNwQ0bq6Q%07q6EgI{V}-I*Ya)fuGrdSD$h;e{9FbNi!!n{p zm`FaKsiA1J5N!N<%xdlWH%+`@vdkLio&;$$p0If`v%Vx7Z!MG2=IW6lrlvE@|CEq+ zGHZl_j<6~WNI}ZVXhiBt{HMt*oa)7-P%jOu^nLgmBgOUo95)l_;+PHhq=FA1B?YO2 zY)QW&`QHY7uXso zCG2y(WI$*{ecjw0fpqhbacA-P`f3W zTY|m$Z}S3ufxRI{A7c>4Z9TT~*=YGn4a9x8^96(9HXV;82W&k&KY9n<(7eJIStV1p zGD;+0RnWQk(V$c>9g=lVF(;jO3}TgY6qhPAkZ=DbM;UBm;c_D}0O(uxvp{B8ZO3undXU#4_nLi;RXn<*a7xhD?p0>k6)* zPE`ldL_>F*^UXlQ9CKDRM}Jto-nwWLQl-%zUZkLglq>^@3w)rq~?9)VnCe-4kUXBPI z4+&ZgMk+3@2&7VOec6aYu(`AVLL=E#|8t|+lBmL1yDrql;sfdt((ITwNE)+Nsy%R&KO3$?&o zy4i$x^Iqzuk*mLmNk07y-*tw;o~Gze^;0KUM}T(`?m-u=JvHt_7R9 zWo%8C7~kroNCbKIVVZDhLLlfrx=RS&V)xsY~Pd&xm#c#=hWi zZ%jZrVHIz?QLI*F)Y4y~!|quo^f89H?GsHr+@x|Ba@|@ygS{&UN^jO$?LMoWm2M0b zOV`+Ex;S-5p={%rSIWOQO+BxsHQulsU$QZNFi~5Z;^x3Mnf~ci9Y?Ff}9xxew~3y;8dy-jJ^SGu? zYbHA9Srar+DZ7tnWpC>HVh#FatookA*|4b?u{7ba_T__Xish z1&R=>(nOVjFlk4YmUe>{dfgmBY0P1V!GU*?T1-#4&fC`5M>w+`!{4rl4RR|MNYwI^ zw<`JdQE3C?aoB-!pO^V0a-_}*9}pEOML;Lo2>Bt#V|8QGMvawzeztcc)8v^rxw$7s z(x5bJ3gxNJsAqU<7$=3RUr7~2{bb5d1bXU5<+&qHZR>}S=+AXTaF47%-g-!MUYVRbifaYweF^vn~Jh7_?xIZFMQ$J%GLQCk} zi_Xe)f&#m;UTX$oOd|17$%?x&t-U11=uqgy}PFtWdzCi5F67C=-A0qaFnr3L}VloysD zND&cmyYy3}gsag@nr7jhs|fDYT`vKi-qA6vPN(ETR$;@kXcf|7v(nrY5g+SPtp@$5 zI@Q~FDX(c;Ld}n)4k&D6;WLyT-jgzfG;0(tespIJ`p}mDc}kM4jj`UY;pb;*SYD@1 zcHJe_ionlJDgmN|urCYA!o#rK>V{hX)D71p`;zy#SQQkGP}%Cl7@BNTK0YItMF&N% zO)hE0PkkPG#`%3a7tNjj7#!whqgndp*@LkuxBA#w8AT#*NWPE3Z#NEG!VC(#WXMjD>lP^YxOhq`9l zEeCt&nRtOqeCZ%*te++XbqL|{<+EELQH+nv`=d!hi2pY;w*;0 zhjMV%Ic8t{m)GvVV?ATM&Z<{)+>(}p#zevUN)=EVQ6o-qo;HPkearqNo{=YPF)y8o z{eqnQw@d6MRkdDX?sl{>^9JNX?r^QgU74@d+LHW(N*l=?VpUHCKGk6OGjF{uJbXhq zHhfp7S`31JLO3kIm=`Va8i671ia5df3tW@g{;p+B&qp$76^vQ9yh14RMwW?;Y?%U3 z7X87mgYQL7TA57m%oTT0_x=y~ k&;RS+;dN(%|9>6-?YI56*2&MR007dnNq^R(73lo+KZI4aSpWb4 literal 3226 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 Date: Wed, 7 Aug 2024 14:14:35 +0000 Subject: [PATCH 55/55] Update docs