diff --git a/Hammerspoon 2/Bridging-Header.h b/Hammerspoon 2/Bridging-Header.h index 609b102d..ff580717 100644 --- a/Hammerspoon 2/Bridging-Header.h +++ b/Hammerspoon 2/Bridging-Header.h @@ -14,3 +14,25 @@ #import JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx); +// IOHIDGetAccelerationWithKey / IOHIDSetAccelerationWithKey were deprecated in macOS 10.12 +// but remain the only public API for reading and writing live mouse-acceleration values +// for the current session. These wrappers silence the deprecation warnings so they can be +// called from Swift without polluting the build log. +#import + +static inline kern_return_t +hs_IOHIDGetAccelerationWithKey(io_connect_t handle, CFStringRef key, double *acceleration) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return IOHIDGetAccelerationWithKey(handle, key, acceleration); +#pragma clang diagnostic pop +} + +static inline kern_return_t +hs_IOHIDSetAccelerationWithKey(io_connect_t handle, CFStringRef key, double acceleration) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return IOHIDSetAccelerationWithKey(handle, key, acceleration); +#pragma clang diagnostic pop +} + diff --git a/Hammerspoon 2/Engine/ModuleRoot.swift b/Hammerspoon 2/Engine/ModuleRoot.swift index 46ecca34..6c4ea962 100644 --- a/Hammerspoon 2/Engine/ModuleRoot.swift +++ b/Hammerspoon 2/Engine/ModuleRoot.swift @@ -86,6 +86,7 @@ import JavaScriptCoreExtras @objc var sound: HSSoundModule { get } @objc var network: HSNetworkModule { get } @objc var window: HSWindowModule { get } + @objc var mouse: HSMouseModule { get } } @_documentation(visibility: private) @@ -196,6 +197,7 @@ import JavaScriptCoreExtras @objc var sound: HSSoundModule { get { getOrCreate(name: "sound", type: HSSoundModule.self)}} @objc var network: HSNetworkModule { get { getOrCreate(name: "network", type: HSNetworkModule.self)}} @objc var window: HSWindowModule { get { getOrCreate(name: "window", type: HSWindowModule.self)}} + @objc var mouse: HSMouseModule { get { getOrCreate(name: "mouse", type: HSMouseModule.self)}} } // MARK: - JSContextInstallable diff --git a/Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift b/Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift new file mode 100644 index 00000000..77fd46ae --- /dev/null +++ b/Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift @@ -0,0 +1,399 @@ +// +// HSMouseModule.swift +// Hammerspoon 2 +// + +import Foundation +import JavaScriptCore +import JavaScriptCoreExtras +import AppKit +import CoreGraphics +import IOKit + +// MARK: - IOKit helpers (file-scope, no actor isolation needed) + +/// Enumerate IOHIDDevice services and filter those whose `PrimaryUsagePage` is 1 (Generic Desktop) +/// and `PrimaryUsage` is 2 (Mouse). Uses the same IOService iteration pattern as hs.usb so that +/// CF-type casting issues are avoided entirely — properties are extracted as `[String: Any]`. +/// +/// When `includeInternal` is `false`, devices whose `Transport` is `"SPI"` are excluded; those +/// are typically the built-in MacBook trackpad. +private func mouseDeviceInfos(includeInternal: Bool) -> [(name: String, transport: String)] { + var iterator: io_iterator_t = IO_OBJECT_NULL + guard unsafe IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOHIDDevice"), &iterator) == KERN_SUCCESS else { + return [] + } + defer { IOObjectRelease(iterator) } + + var result: [(name: String, transport: String)] = [] + var service = IOIteratorNext(iterator) + while service != IO_OBJECT_NULL { + defer { + IOObjectRelease(service) + service = IOIteratorNext(iterator) + } + + var propertiesRef: Unmanaged? + guard unsafe IORegistryEntryCreateCFProperties(service, &propertiesRef, kCFAllocatorDefault, 0) == KERN_SUCCESS, + let props = unsafe propertiesRef?.takeRetainedValue() as? [String: Any] else { continue } + + // Filter to mouse usage class (kHIDPage_GenericDesktop = 1, kHIDUsage_GD_Mouse = 2). + guard let usagePage = props["PrimaryUsagePage"] as? Int, usagePage == 1, + let usage = props["PrimaryUsage"] as? Int, usage == 2 else { continue } + + let name = props["Product"] as? String ?? "Unknown" + let transport = props["Transport"] as? String ?? "" + if !includeInternal && transport == "SPI" { continue } + result.append((name: name, transport: transport)) + } + return result +} + +/// Opens a connection to the IOHIDSystem event driver for reading/writing HID parameters. +/// The caller is responsible for calling `IOServiceClose` on the returned handle when done. +/// Returns `IO_OBJECT_NULL` on failure. +private func openHIDEventDriver() -> io_connect_t { + let service = unsafe IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOHIDSystem")) + guard service != IO_OBJECT_NULL else { return IO_OBJECT_NULL } + defer { IOObjectRelease(service) } + var connect: io_connect_t = IO_OBJECT_NULL + // kIOHIDParamConnectType = 1 (IOKit/hidsystem/IOHIDShared.h) + let kr: kern_return_t = unsafe IOServiceOpen(service, mach_task_self_, 1, &connect) + guard kr == KERN_SUCCESS else { + return IO_OBJECT_NULL + } + return connect +} + +// MARK: - Module API + +/// Control and inspect the mouse pointer and attached mouse devices. +/// +/// ## Position +/// +/// All coordinates use **Hammerspoon screen coordinates**: `(0, 0)` is at the top-left +/// of the primary display and `y` increases downward. +/// +/// ```js +/// const pos = hs.mouse.absolutePosition() +/// console.log("Mouse at " + pos.x + ", " + pos.y) +/// +/// hs.mouse.setAbsolutePosition(100, 200) +/// ``` +/// +/// ## Device info +/// +/// ```js +/// console.log("Mice: " + hs.mouse.count()) +/// hs.mouse.names().forEach(n => console.log(n)) +/// ``` +/// +/// ## Cursor +/// +/// ```js +/// console.log(hs.mouse.currentCursorType()) // e.g. "arrow" +/// console.log(hs.mouse.scrollDirection()) // "natural" or "normal" +/// ``` +@objc protocol HSMouseModuleAPI: JSExport { + + // MARK: - Position + + /// Returns the current mouse pointer position in Hammerspoon screen coordinates. + /// + /// Hammerspoon coordinates have `(0, 0)` at the top-left of the primary display, + /// with `y` increasing downward. + /// - Returns: An object with `x` and `y` number properties. + /// - Example: + /// ```js + /// const pos = hs.mouse.absolutePosition() + /// console.log("x=" + pos.x + " y=" + pos.y) + /// ``` + @objc func absolutePosition() -> [String: Double] + + /// Moves the mouse pointer to the specified absolute position in Hammerspoon screen coordinates. + /// + /// - Parameter x: Horizontal position; `0` is the left edge of the primary display. + /// - Parameter y: Vertical position; `0` is the top edge of the primary display. + /// - Example: + /// ```js + /// hs.mouse.setAbsolutePosition(100, 200) + /// ``` + @objc func setAbsolutePosition(_ x: Double, _ y: Double) + + /// Returns the mouse pointer position relative to the screen it is currently on. + /// + /// The returned coordinates have `(0, 0)` at the top-left corner of the screen + /// that the cursor is on. + /// - Returns: An object with `x` and `y` number properties, or `null` if no screen can be determined. + /// - Example: + /// ```js + /// const rel = hs.mouse.getRelativePosition() + /// if (rel) console.log("x=" + rel.x + " y=" + rel.y) + /// ``` + @objc func getRelativePosition() -> [String: Double]? + + /// Moves the mouse pointer to a position relative to the screen it is currently on. + /// + /// - Parameter x: Horizontal offset from the current screen's left edge. + /// - Parameter y: Vertical offset from the current screen's top edge. + /// - Example: + /// ```js + /// hs.mouse.setRelativePosition(0, 0) // move to top-left of current screen + /// ``` + @objc func setRelativePosition(_ x: Double, _ y: Double) + + // MARK: - Screen + + /// Returns the screen that the mouse pointer is currently on. + /// + /// - Returns: An HSScreen object for the display containing the cursor, or `null` if none can be determined. + /// - Example: + /// ```js + /// const s = hs.mouse.getCurrentScreen() + /// if (s) console.log("Mouse is on: " + s.name) + /// ``` + @objc func getCurrentScreen() -> HSScreen? + + // MARK: - Devices + + /// Returns the number of mouse devices currently attached to the system. + /// + /// - Parameter includeInternal: When `true`, built-in pointing devices (e.g. the MacBook built-in trackpad) are included. Defaults to `false`. + /// - Returns: The number of attached mouse devices. + /// - Example: + /// ```js + /// console.log("External mice: " + hs.mouse.count()) + /// console.log("All pointing devices: " + hs.mouse.count(true)) + /// ``` + @objc func count(_ includeInternal: Bool) -> Int + + /// Returns the product names of all mouse devices currently attached to the system. + /// + /// - Parameter includeInternal: When `true`, built-in pointing devices are included. Defaults to `false`. + /// - Returns: An array of product name strings. + /// - Example: + /// ```js + /// hs.mouse.names().forEach(n => console.log(n)) + /// ``` + @objc func names(_ includeInternal: Bool) -> [String] + + // MARK: - Settings + + /// Returns the current mouse tracking speed (acceleration level). + /// + /// Values range from `-1.0` (system default, acceleration disabled) to `3.0` (maximum acceleration). + /// Returns `-1.0` if the value cannot be read. + /// - Returns: The current tracking speed as a number. + /// - Example: + /// ```js + /// console.log("Tracking speed: " + hs.mouse.trackingSpeed()) + /// ``` + @objc func trackingSpeed() -> Double + + /// Sets the mouse tracking speed (acceleration level). + /// + /// The change takes effect immediately for the current login session and is also persisted + /// to preferences so it survives a restart. Values outside the valid range or non-finite + /// values are rejected with a warning and no change is made. + /// - Parameter speed: Desired tracking speed in the range `-1.0` to `3.0`. + /// - Example: + /// ```js + /// hs.mouse.setTrackingSpeed(1.5) + /// ``` + @objc func setTrackingSpeed(_ speed: Double) + + /// Returns the current scroll wheel direction setting. + /// + /// - Returns: `"natural"` if content scrolls in the same direction as the finger/wheel movement (macOS default), or `"normal"` for the traditional direction. + /// - Example: + /// ```js + /// console.log(hs.mouse.scrollDirection()) + /// ``` + @objc func scrollDirection() -> String + + // MARK: - Cursor + + /// Returns the name of the cursor type currently set by this application. + /// + /// - Note: This reflects the cursor set by the Hammerspoon process. If another application + /// has the keyboard focus, the visible system cursor may differ. + /// - Returns: A string such as `"arrow"`, `"iBeam"`, `"crosshair"`, `"pointingHand"`, + /// `"openHand"`, `"closedHand"`, `"resizeLeft"`, `"resizeRight"`, `"resizeLeftRight"`, + /// `"resizeUp"`, `"resizeDown"`, `"resizeUpDown"`, `"operationNotAllowed"`, + /// `"dragLink"`, `"dragCopy"`, `"contextualMenu"`, + /// `"iBeamCursorForVerticalLayout"`, or `"unknown"`. + /// - Example: + /// ```js + /// console.log(hs.mouse.currentCursorType()) + /// ``` + @objc func currentCursorType() -> String +} + +// MARK: - Implementation + +@_documentation(visibility: private) +@MainActor +@objc class HSMouseModule: NSObject, HSModuleAPI, HSMouseModuleAPI { + var name = "hs.mouse" + let engineID: UUID + + required init(engineID: UUID) { + self.engineID = engineID + super.init() + AKDebug("Init of \(name): \(engineID)") + } + + func shutdown() {} + + isolated deinit { + AKDebug("Deinit of \(name): \(engineID)") + } + + // MARK: - Position + + @objc func absolutePosition() -> [String: Double] { + let loc = NSEvent.mouseLocation + // NSEvent.mouseLocation uses AppKit coordinates (y=0 at bottom of primary screen, y-up). + // Convert to Hammerspoon coordinates (y=0 at top of primary screen, y-down). + // The primary screen is the one whose AppKit frame origin is at (0, 0). + let primaryHeight = NSScreen.screens + .first(where: { $0.frame.origin == .zero })? + .frame.height + ?? NSScreen.screens.first?.frame.height + ?? 0 + return ["x": Double(loc.x), "y": Double(primaryHeight - loc.y)] + } + + @objc func setAbsolutePosition(_ x: Double, _ y: Double) { + // CGWarpMouseCursorPosition uses global display coordinates: + // (0,0) = top-left of primary display, y increases downward — same as Hammerspoon. + CGWarpMouseCursorPosition(CGPoint(x: x, y: y)) + } + + @objc func getRelativePosition() -> [String: Double]? { + guard let screen = getCurrentScreen() else { return nil } + let abs = absolutePosition() + let sx = screen.position.x + let sy = screen.position.y + return ["x": (abs["x"] ?? 0) - sx, "y": (abs["y"] ?? 0) - sy] + } + + @objc func setRelativePosition(_ x: Double, _ y: Double) { + guard let screen = getCurrentScreen() else { return } + let sx = screen.position.x + let sy = screen.position.y + setAbsolutePosition(sx + x, sy + y) + } + + // MARK: - Screen + + @objc func getCurrentScreen() -> HSScreen? { + // NSEvent.mouseLocation is in AppKit coordinates (y-up from bottom of primary screen). + // NSScreen.frame is also in AppKit coordinates, so the containment check is direct. + let loc = NSEvent.mouseLocation + for screen in NSScreen.screens { + if screen.frame.contains(loc) { + return HSScreen(screen: screen) + } + } + return nil + } + + // MARK: - Devices + + @objc func count(_ includeInternal: Bool) -> Int { + mouseDeviceInfos(includeInternal: includeInternal).count + } + + @objc func names(_ includeInternal: Bool) -> [String] { + mouseDeviceInfos(includeInternal: includeInternal).map { $0.name } + } + + // MARK: - Settings + + @objc func trackingSpeed() -> Double { + let connect = openHIDEventDriver() + guard connect != IO_OBJECT_NULL else { + AKWarning("hs.mouse.trackingSpeed(): Failed to open HID event driver") + return -1.0 + } + defer { IOServiceClose(connect) } + var speed: Double = -1.0 + _ = unsafe hs_IOHIDGetAccelerationWithKey(connect, "HIDMouseAcceleration" as CFString, &speed) + return speed + } + + @objc func setTrackingSpeed(_ speed: Double) { + guard speed.isFinite && speed >= -1.0 && speed <= 3.0 else { + AKWarning("hs.mouse.setTrackingSpeed(): speed must be in the range -1.0 to 3.0 (got \(speed))") + return + } + let connect = openHIDEventDriver() + guard connect != IO_OBJECT_NULL else { + AKWarning("hs.mouse.setTrackingSpeed(): Failed to open HID event driver") + return + } + defer { IOServiceClose(connect) } + _ = hs_IOHIDSetAccelerationWithKey(connect, "HIDMouseAcceleration" as CFString, speed) + + // Persist so the value survives a restart. + CFPreferencesSetValue( + "com.apple.mouse.scaling" as CFString, + NSNumber(value: speed), + kCFPreferencesAnyApplication, + kCFPreferencesCurrentUser, + kCFPreferencesAnyHost + ) + CFPreferencesSynchronize( + kCFPreferencesAnyApplication, + kCFPreferencesCurrentUser, + kCFPreferencesAnyHost + ) + } + + @objc func scrollDirection() -> String { + let val = CFPreferencesCopyValue( + "com.apple.swipescrolldirection" as CFString, + kCFPreferencesAnyApplication, + kCFPreferencesCurrentUser, + kCFPreferencesAnyHost + ) + // `true` (or missing) means natural scrolling (macOS default since Lion). + let isNatural = (val as? NSNumber)?.boolValue ?? true + return isNatural ? "natural" : "normal" + } + + // MARK: - Cursor + + @objc func currentCursorType() -> String { + let current = NSCursor.current + guard let currentTiff = current.image.tiffRepresentation else { return "unknown" } + + let knownCursors: [(String, NSCursor)] = [ + ("arrow", .arrow), + ("iBeam", .iBeam), + ("crosshair", .crosshair), + ("closedHand", .closedHand), + ("openHand", .openHand), + ("pointingHand", .pointingHand), + ("resizeLeft", .resizeLeft), + ("resizeRight", .resizeRight), + ("resizeLeftRight", .resizeLeftRight), + ("resizeUp", .resizeUp), + ("resizeDown", .resizeDown), + ("resizeUpDown", .resizeUpDown), + ("iBeamCursorForVerticalLayout", .iBeamCursorForVerticalLayout), + ("operationNotAllowed", .operationNotAllowed), + ("dragLink", .dragLink), + ("dragCopy", .dragCopy), + ("contextualMenu", .contextualMenu), + ] + + for (typeName, cursor) in knownCursors { + if cursor.image.tiffRepresentation == currentTiff { + return typeName + } + } + return "unknown" + } +} diff --git a/Hammerspoon 2Tests/Helpers/JSTestHarness.swift b/Hammerspoon 2Tests/Helpers/JSTestHarness.swift index 8b86c40f..c0eb0b68 100644 --- a/Hammerspoon 2Tests/Helpers/JSTestHarness.swift +++ b/Hammerspoon 2Tests/Helpers/JSTestHarness.swift @@ -482,6 +482,8 @@ extension JSTestHarness { loadModule(HSShortcutsModule.self, as: name) case "ipc": loadModule(HSIPCModule.self, as: name) + case "mouse": + loadModule(HSMouseModule.self, as: name) default: print("⚠️ Unknown module: \(name)") } diff --git a/Hammerspoon 2Tests/IntegrationTests/HSMouseIntegrationTests.swift b/Hammerspoon 2Tests/IntegrationTests/HSMouseIntegrationTests.swift new file mode 100644 index 00000000..1bd353ce --- /dev/null +++ b/Hammerspoon 2Tests/IntegrationTests/HSMouseIntegrationTests.swift @@ -0,0 +1,280 @@ +// +// HSMouseIntegrationTests.swift +// Hammerspoon 2Tests +// + +import Testing +import JavaScriptCore +@testable import Hammerspoon_2 + +@Suite("hs.mouse tests") +struct HSMouseTests { + + // MARK: - Suite 1: API structure + + @Suite("hs.mouse API structure tests") + struct HSMouseStructureTests { + + private func makeHarness() -> JSTestHarness { + let harness = JSTestHarness() + harness.loadModule(HSMouseModule.self, as: "mouse") + return harness + } + + // MARK: Position functions + + @Test("absolutePosition is a function") + func testAbsolutePositionIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.absolutePosition === 'function'") + } + + @Test("setAbsolutePosition is a function") + func testSetAbsolutePositionIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.setAbsolutePosition === 'function'") + } + + @Test("getRelativePosition is a function") + func testGetRelativePositionIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.getRelativePosition === 'function'") + } + + @Test("setRelativePosition is a function") + func testSetRelativePositionIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.setRelativePosition === 'function'") + } + + // MARK: Screen functions + + @Test("getCurrentScreen is a function") + func testGetCurrentScreenIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.getCurrentScreen === 'function'") + } + + // MARK: Device functions + + @Test("count is a function") + func testCountIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.count === 'function'") + } + + @Test("names is a function") + func testNamesIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.names === 'function'") + } + + // MARK: Settings functions + + @Test("trackingSpeed is a function") + func testTrackingSpeedIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.trackingSpeed === 'function'") + } + + @Test("setTrackingSpeed is a function") + func testSetTrackingSpeedIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.setTrackingSpeed === 'function'") + } + + @Test("scrollDirection is a function") + func testScrollDirectionIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.scrollDirection === 'function'") + } + + // MARK: Cursor functions + + @Test("currentCursorType is a function") + func testCurrentCursorTypeIsFunction() { + makeHarness().expectTrue("typeof hs.mouse.currentCursorType === 'function'") + } + } + + // MARK: - Suite 2: Behaviour + + @Suite("hs.mouse behaviour tests") + struct HSMouseBehaviourTests { + + private func makeHarness() -> JSTestHarness { + let harness = JSTestHarness() + harness.loadModule(HSMouseModule.self, as: "mouse") + return harness + } + + // MARK: absolutePosition + + @Test("absolutePosition() returns an object with x and y numbers") + func testAbsolutePositionShape() { + let harness = makeHarness() + harness.eval("var pos = hs.mouse.absolutePosition()") + harness.expectTrue("typeof pos === 'object' && pos !== null") + harness.expectTrue("typeof pos.x === 'number'") + harness.expectTrue("typeof pos.y === 'number'") + #expect(!harness.hasException) + } + + @Test("absolutePosition() x is non-negative") + func testAbsolutePositionXNonNegative() { + let harness = makeHarness() + harness.eval("var pos = hs.mouse.absolutePosition()") + harness.expectTrue("pos.x >= 0") + #expect(!harness.hasException) + } + + @Test("absolutePosition() y is non-negative") + func testAbsolutePositionYNonNegative() { + let harness = makeHarness() + harness.eval("var pos = hs.mouse.absolutePosition()") + harness.expectTrue("pos.y >= 0") + #expect(!harness.hasException) + } + + // MARK: setAbsolutePosition + + @Test("setAbsolutePosition() does not throw") + func testSetAbsolutePositionDoesNotThrow() { + let harness = makeHarness() + let before = harness.evalValue("hs.mouse.absolutePosition()")?.toDictionary() + harness.eval("hs.mouse.setAbsolutePosition(hs.mouse.absolutePosition().x, hs.mouse.absolutePosition().y)") + #expect(!harness.hasException) + _ = before + } + + // MARK: getRelativePosition + + @Test("getRelativePosition() returns an object or null") + func testGetRelativePositionShape() { + let harness = makeHarness() + harness.eval("var rel = hs.mouse.getRelativePosition()") + harness.expectTrue("rel === null || (typeof rel === 'object' && typeof rel.x === 'number' && typeof rel.y === 'number')") + #expect(!harness.hasException) + } + + // MARK: count + + @Test("count() returns a non-negative integer") + func testCountNonNegative() { + let harness = makeHarness() + harness.eval("var n = hs.mouse.count()") + harness.expectTrue("typeof n === 'number' && n >= 0 && Math.floor(n) === n") + #expect(!harness.hasException) + } + + @Test("count(true) >= count(false)") + func testCountIncludesInternalIsLargerOrEqual() { + let harness = makeHarness() + harness.eval("var external = hs.mouse.count(false)") + harness.eval("var all = hs.mouse.count(true)") + harness.expectTrue("all >= external") + #expect(!harness.hasException) + } + + // MARK: names + + @Test("names() returns an array") + func testNamesReturnsArray() { + let harness = makeHarness() + harness.expectTrue("Array.isArray(hs.mouse.names())") + #expect(!harness.hasException) + } + + @Test("names() length matches count()") + func testNamesLengthMatchesCount() { + let harness = makeHarness() + harness.eval("var n = hs.mouse.count()") + harness.eval("var names = hs.mouse.names()") + harness.expectTrue("names.length === n") + #expect(!harness.hasException) + } + + @Test("names(true) length matches count(true)") + func testNamesIncludeInternalLengthMatchesCount() { + let harness = makeHarness() + harness.eval("var n = hs.mouse.count(true)") + harness.eval("var names = hs.mouse.names(true)") + harness.expectTrue("names.length === n") + #expect(!harness.hasException) + } + + @Test("names() elements are non-empty strings") + func testNamesElementsAreStrings() { + let harness = makeHarness() + harness.eval("var names = hs.mouse.names(true)") + harness.expectTrue("names.every(function(n) { return typeof n === 'string' && n.length > 0 })") + #expect(!harness.hasException) + } + + // MARK: scrollDirection + + @Test("scrollDirection() returns 'natural' or 'normal'") + func testScrollDirectionIsValidString() { + let harness = makeHarness() + harness.eval("var dir = hs.mouse.scrollDirection()") + harness.expectTrue("dir === 'natural' || dir === 'normal'") + #expect(!harness.hasException) + } + + // MARK: trackingSpeed + + @Test("trackingSpeed() returns a number") + func testTrackingSpeedIsNumber() { + let harness = makeHarness() + harness.expectTrue("typeof hs.mouse.trackingSpeed() === 'number'") + #expect(!harness.hasException) + } + + // MARK: currentCursorType + + @Test("currentCursorType() returns a non-empty string") + func testCurrentCursorTypeIsString() { + let harness = makeHarness() + harness.eval("var ct = hs.mouse.currentCursorType()") + harness.expectTrue("typeof ct === 'string' && ct.length > 0") + #expect(!harness.hasException) + } + + @Test("currentCursorType() returns a known type name or 'unknown'") + func testCurrentCursorTypeIsKnownValue() { + let harness = makeHarness() + harness.eval(""" + var ct = hs.mouse.currentCursorType() + var known = ['arrow','iBeam','crosshair','closedHand','openHand','pointingHand', + 'resizeLeft','resizeRight','resizeLeftRight','resizeUp','resizeDown', + 'resizeUpDown','iBeamCursorForVerticalLayout','operationNotAllowed', + 'dragLink','dragCopy','contextualMenu','unknown'] + """) + harness.expectTrue("known.indexOf(ct) !== -1") + #expect(!harness.hasException) + } + + // MARK: getCurrentScreen + + @Test("getCurrentScreen() returns an object or null") + func testGetCurrentScreenReturnsObjectOrNull() { + let harness = makeHarness() + harness.eval("var s = hs.mouse.getCurrentScreen()") + harness.expectTrue("s === null || typeof s === 'object'") + #expect(!harness.hasException) + } + + @Test("getCurrentScreen() result has name property when not null") + func testGetCurrentScreenHasName() { + let harness = makeHarness() + harness.eval("var s = hs.mouse.getCurrentScreen()") + harness.expectTrue("s === null || typeof s.name === 'string'") + #expect(!harness.hasException) + } + + // MARK: setRelativePosition + + @Test("setRelativePosition() does not throw") + func testSetRelativePositionDoesNotThrow() { + let harness = makeHarness() + // Get current relative position and set it back — net zero movement + harness.eval(""" + var rel = hs.mouse.getRelativePosition() + if (rel !== null) { + hs.mouse.setRelativePosition(rel.x, rel.y) + } + """) + #expect(!harness.hasException) + } + } +} diff --git a/docs/api.json b/docs/api.json index 6f204134..c783bfc1 100644 --- a/docs/api.json +++ b/docs/api.json @@ -10238,6 +10238,304 @@ "description": "Module for creating and managing macOS system menu bar items.\nMenu bar items appear in the right side of the macOS menu bar (alongside the clock, Wi-Fi icon, etc.).\nEach item can display a title, an icon, or both, and can open a menu or invoke a callback when clicked.\n## Creating a simple title item\n```js\nconst item = hs.menubar.create()\nitem.title = \"Hello\"\nitem.setClickCallback(() => console.log(\"clicked!\"))\n```\n## Creating an icon item with a static menu\n```js\nconst item = hs.menubar.create()\nitem.setIcon(HSImage.fromSymbol(\"star.fill\"))\nitem.setTooltip(\"My automation\")\nitem.setMenu([\n { title: \"Reload config\", fn: () => hs.reload() },\n { title: \"-\" },\n { title: \"Remove from menubar\", fn: () => item.hide() }\n])\n```\n## Creating an item with a dynamic menu\n```js\nconst item = hs.menubar.create()\nitem.title = \"Dynamic\"\nitem.setMenu(() => [\n { title: \"Time: \" + new Date().toLocaleTimeString() },\n { title: \"-\" },\n { title: \"Remove from menubar\", fn: () => item.hide() }\n])\n```", "rawDocumentation": "Module for creating and managing macOS system menu bar items.\n\nMenu bar items appear in the right side of the macOS menu bar (alongside the clock, Wi-Fi icon, etc.).\nEach item can display a title, an icon, or both, and can open a menu or invoke a callback when clicked.\n\n## Creating a simple title item\n\n```js\nconst item = hs.menubar.create()\nitem.title = \"Hello\"\nitem.setClickCallback(() => console.log(\"clicked!\"))\n```\n\n## Creating an icon item with a static menu\n\n```js\nconst item = hs.menubar.create()\nitem.setIcon(HSImage.fromSymbol(\"star.fill\"))\nitem.setTooltip(\"My automation\")\nitem.setMenu([\n { title: \"Reload config\", fn: () => hs.reload() },\n { title: \"-\" },\n { title: \"Remove from menubar\", fn: () => item.hide() }\n])\n```\n\n## Creating an item with a dynamic menu\n\n```js\nconst item = hs.menubar.create()\nitem.title = \"Dynamic\"\nitem.setMenu(() => [\n { title: \"Time: \" + new Date().toLocaleTimeString() },\n { title: \"-\" },\n { title: \"Remove from menubar\", fn: () => item.hide() }\n])\n```" }, + { + "name": "hs.mouse", + "methods": [ + { + "name": "absolutePosition", + "signature": "func absolutePosition() -> [String: Double]", + "isStatic": false, + "rawDocumentation": "Returns the current mouse pointer position in Hammerspoon screen coordinates.\n\nHammerspoon coordinates have `(0, 0)` at the top-left of the primary display,\nwith `y` increasing downward.\n- Returns: An object with `x` and `y` number properties.\n- Example:\n```js\nconst pos = hs.mouse.absolutePosition()\nconsole.log(\"x=\" + pos.x + \" y=\" + pos.y)\n```", + "description": "Returns the current mouse pointer position in Hammerspoon screen coordinates.\nHammerspoon coordinates have `(0, 0)` at the top-left of the primary display,\nwith `y` increasing downward.", + "params": [], + "returns": { + "type": "Object", + "description": "An object with `x` and `y` number properties." + }, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "const pos = hs.mouse.absolutePosition()\nconsole.log(\"x=\" + pos.x + \" y=\" + pos.y)" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 111 + }, + { + "name": "setAbsolutePosition", + "signature": "func setAbsolutePosition(_ x: Double, _ y: Double)", + "isStatic": false, + "rawDocumentation": "Moves the mouse pointer to the specified absolute position in Hammerspoon screen coordinates.\n\n- Parameter x: Horizontal position; `0` is the left edge of the primary display.\n- Parameter y: Vertical position; `0` is the top edge of the primary display.\n- Example:\n```js\nhs.mouse.setAbsolutePosition(100, 200)\n```", + "description": "Moves the mouse pointer to the specified absolute position in Hammerspoon screen coordinates.", + "params": [ + { + "name": "x", + "type": "number", + "description": "Horizontal position; `0` is the left edge of the primary display.", + "optional": false, + "tsType": null + }, + { + "name": "y", + "type": "number", + "description": "Vertical position; `0` is the top edge of the primary display.", + "optional": false, + "tsType": null + } + ], + "returns": null, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "hs.mouse.setAbsolutePosition(100, 200)" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 121 + }, + { + "name": "getRelativePosition", + "signature": "func getRelativePosition() -> [String: Double]?", + "isStatic": false, + "rawDocumentation": "Returns the mouse pointer position relative to the screen it is currently on.\n\nThe returned coordinates have `(0, 0)` at the top-left corner of the screen\nthat the cursor is on.\n- Returns: An object with `x` and `y` number properties, or `null` if no screen can be determined.\n- Example:\n```js\nconst rel = hs.mouse.getRelativePosition()\nif (rel) console.log(\"x=\" + rel.x + \" y=\" + rel.y)\n```", + "description": "Returns the mouse pointer position relative to the screen it is currently on.\nThe returned coordinates have `(0, 0)` at the top-left corner of the screen\nthat the cursor is on.", + "params": [], + "returns": { + "type": "Object", + "description": "An object with `x` and `y` number properties, or `null` if no screen can be determined." + }, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "const rel = hs.mouse.getRelativePosition()\nif (rel) console.log(\"x=\" + rel.x + \" y=\" + rel.y)" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 133 + }, + { + "name": "setRelativePosition", + "signature": "func setRelativePosition(_ x: Double, _ y: Double)", + "isStatic": false, + "rawDocumentation": "Moves the mouse pointer to a position relative to the screen it is currently on.\n\n- Parameter x: Horizontal offset from the current screen's left edge.\n- Parameter y: Vertical offset from the current screen's top edge.\n- Example:\n```js\nhs.mouse.setRelativePosition(0, 0) // move to top-left of current screen\n```", + "description": "Moves the mouse pointer to a position relative to the screen it is currently on.", + "params": [ + { + "name": "x", + "type": "number", + "description": "Horizontal offset from the current screen's left edge.", + "optional": false, + "tsType": null + }, + { + "name": "y", + "type": "number", + "description": "Vertical offset from the current screen's top edge.", + "optional": false, + "tsType": null + } + ], + "returns": null, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "hs.mouse.setRelativePosition(0, 0) // move to top-left of current screen" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 143 + }, + { + "name": "getCurrentScreen", + "signature": "func getCurrentScreen() -> HSScreen?", + "isStatic": false, + "rawDocumentation": "Returns the screen that the mouse pointer is currently on.\n\n- Returns: An HSScreen object for the display containing the cursor, or `null` if none can be determined.\n- Example:\n```js\nconst s = hs.mouse.getCurrentScreen()\nif (s) console.log(\"Mouse is on: \" + s.name)\n```", + "description": "Returns the screen that the mouse pointer is currently on.", + "params": [], + "returns": { + "type": "HSScreen", + "description": "An HSScreen object for the display containing the cursor, or `null` if none can be determined." + }, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "const s = hs.mouse.getCurrentScreen()\nif (s) console.log(\"Mouse is on: \" + s.name)" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 155 + }, + { + "name": "count", + "signature": "func count(_ includeInternal: Bool) -> Int", + "isStatic": false, + "rawDocumentation": "Returns the number of mouse devices currently attached to the system.\n\n- Parameter includeInternal: When `true`, built-in pointing devices (e.g. the MacBook built-in trackpad) are included. Defaults to `false`.\n- Returns: The number of attached mouse devices.\n- Example:\n```js\nconsole.log(\"External mice: \" + hs.mouse.count())\nconsole.log(\"All pointing devices: \" + hs.mouse.count(true))\n```", + "description": "Returns the number of mouse devices currently attached to the system.", + "params": [ + { + "name": "includeInternal", + "type": "boolean", + "description": "When `true`, built-in pointing devices (e.g. the MacBook built-in trackpad) are included. Defaults to `false`.", + "optional": false, + "tsType": null + } + ], + "returns": { + "type": "number", + "description": "The number of attached mouse devices." + }, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "console.log(\"External mice: \" + hs.mouse.count())\nconsole.log(\"All pointing devices: \" + hs.mouse.count(true))" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 168 + }, + { + "name": "names", + "signature": "func names(_ includeInternal: Bool) -> [String]", + "isStatic": false, + "rawDocumentation": "Returns the product names of all mouse devices currently attached to the system.\n\n- Parameter includeInternal: When `true`, built-in pointing devices are included. Defaults to `false`.\n- Returns: An array of product name strings.\n- Example:\n```js\nhs.mouse.names().forEach(n => console.log(n))\n```", + "description": "Returns the product names of all mouse devices currently attached to the system.", + "params": [ + { + "name": "includeInternal", + "type": "boolean", + "description": "When `true`, built-in pointing devices are included. Defaults to `false`.", + "optional": false, + "tsType": null + } + ], + "returns": { + "type": "Array", + "description": "An array of product name strings." + }, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "hs.mouse.names().forEach(n => console.log(n))" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 178 + }, + { + "name": "trackingSpeed", + "signature": "func trackingSpeed() -> Double", + "isStatic": false, + "rawDocumentation": "Returns the current mouse tracking speed (acceleration level).\n\nValues range from `-1.0` (system default, acceleration disabled) to `3.0` (maximum acceleration).\nReturns `-1.0` if the value cannot be read.\n- Returns: The current tracking speed as a number.\n- Example:\n```js\nconsole.log(\"Tracking speed: \" + hs.mouse.trackingSpeed())\n```", + "description": "Returns the current mouse tracking speed (acceleration level).\nValues range from `-1.0` (system default, acceleration disabled) to `3.0` (maximum acceleration).\nReturns `-1.0` if the value cannot be read.", + "params": [], + "returns": { + "type": "number", + "description": "The current tracking speed as a number." + }, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "console.log(\"Tracking speed: \" + hs.mouse.trackingSpeed())" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 191 + }, + { + "name": "setTrackingSpeed", + "signature": "func setTrackingSpeed(_ speed: Double)", + "isStatic": false, + "rawDocumentation": "Sets the mouse tracking speed (acceleration level).\n\nThe change takes effect immediately for the current login session and is also persisted\nto preferences so it survives a restart. Values outside the valid range or non-finite\nvalues are rejected with a warning and no change is made.\n- Parameter speed: Desired tracking speed in the range `-1.0` to `3.0`.\n- Example:\n```js\nhs.mouse.setTrackingSpeed(1.5)\n```", + "description": "Sets the mouse tracking speed (acceleration level).\nThe change takes effect immediately for the current login session and is also persisted\nto preferences so it survives a restart. Values outside the valid range or non-finite\nvalues are rejected with a warning and no change is made.", + "params": [ + { + "name": "speed", + "type": "number", + "description": "Desired tracking speed in the range `-1.0` to `3.0`.", + "optional": false, + "tsType": null + } + ], + "returns": null, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "hs.mouse.setTrackingSpeed(1.5)" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 203 + }, + { + "name": "scrollDirection", + "signature": "func scrollDirection() -> String", + "isStatic": false, + "rawDocumentation": "Returns the current scroll wheel direction setting.\n\n- Returns: `\"natural\"` if content scrolls in the same direction as the finger/wheel movement (macOS default), or `\"normal\"` for the traditional direction.\n- Example:\n```js\nconsole.log(hs.mouse.scrollDirection())\n```", + "description": "Returns the current scroll wheel direction setting.", + "params": [], + "returns": { + "type": "string", + "description": "`\"natural\"` if content scrolls in the same direction as the finger/wheel movement (macOS default), or `\"normal\"` for the traditional direction." + }, + "notes": [], + "examples": [ + { + "lang": "js", + "code": "console.log(hs.mouse.scrollDirection())" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 212 + }, + { + "name": "currentCursorType", + "signature": "func currentCursorType() -> String", + "isStatic": false, + "rawDocumentation": "Returns the name of the cursor type currently set by this application.\n\n- Note: This reflects the cursor set by the Hammerspoon process. If another application\n has the keyboard focus, the visible system cursor may differ.\n- Returns: A string such as `\"arrow\"`, `\"iBeam\"`, `\"crosshair\"`, `\"pointingHand\"`,\n `\"openHand\"`, `\"closedHand\"`, `\"resizeLeft\"`, `\"resizeRight\"`, `\"resizeLeftRight\"`,\n `\"resizeUp\"`, `\"resizeDown\"`, `\"resizeUpDown\"`, `\"operationNotAllowed\"`,\n `\"dragLink\"`, `\"dragCopy\"`, `\"contextualMenu\"`,\n `\"iBeamCursorForVerticalLayout\"`, or `\"unknown\"`.\n- Example:\n```js\nconsole.log(hs.mouse.currentCursorType())\n```", + "description": "Returns the name of the cursor type currently set by this application.\nhas the keyboard focus, the visible system cursor may differ.", + "params": [], + "returns": { + "type": "string", + "description": "A string such as `\"arrow\"`, `\"iBeam\"`, `\"crosshair\"`, `\"pointingHand\"`," + }, + "notes": [ + "This reflects the cursor set by the Hammerspoon process. If another application" + ], + "examples": [ + { + "lang": "js", + "code": "console.log(hs.mouse.currentCursorType())" + } + ], + "source": "swift", + "filePath": "Hammerspoon 2/Modules/hs.mouse/HSMouseModule.swift", + "lineNumber": 229 + } + ], + "properties": [], + "types": [], + "description": "Control and inspect the mouse pointer and attached mouse devices.\n## Position\nAll coordinates use **Hammerspoon screen coordinates**: `(0, 0)` is at the top-left\nof the primary display and `y` increases downward.\n```js\nconst pos = hs.mouse.absolutePosition()\nconsole.log(\"Mouse at \" + pos.x + \", \" + pos.y)\n\nhs.mouse.setAbsolutePosition(100, 200)\n```\n## Device info\n```js\nconsole.log(\"Mice: \" + hs.mouse.count())\nhs.mouse.names().forEach(n => console.log(n))\n```\n## Cursor\n```js\nconsole.log(hs.mouse.currentCursorType()) // e.g. \"arrow\"\nconsole.log(hs.mouse.scrollDirection()) // \"natural\" or \"normal\"\n```", + "rawDocumentation": "Control and inspect the mouse pointer and attached mouse devices.\n\n## Position\n\nAll coordinates use **Hammerspoon screen coordinates**: `(0, 0)` is at the top-left\nof the primary display and `y` increases downward.\n\n```js\nconst pos = hs.mouse.absolutePosition()\nconsole.log(\"Mouse at \" + pos.x + \", \" + pos.y)\n\nhs.mouse.setAbsolutePosition(100, 200)\n```\n\n## Device info\n\n```js\nconsole.log(\"Mice: \" + hs.mouse.count())\nhs.mouse.names().forEach(n => console.log(n))\n```\n\n## Cursor\n\n```js\nconsole.log(hs.mouse.currentCursorType()) // e.g. \"arrow\"\nconsole.log(hs.mouse.scrollDirection()) // \"natural\" or \"normal\"\n```" + }, { "name": "hs.network", "methods": [ @@ -20909,5 +21207,5 @@ "types": [] } ], - "generatedAt": "2026-07-21T20:33:35.487Z" + "generatedAt": "2026-07-23T12:34:00.014Z" } \ No newline at end of file diff --git a/docs/hammerspoon.d.ts b/docs/hammerspoon.d.ts index 661d0113..b910aa68 100644 --- a/docs/hammerspoon.d.ts +++ b/docs/hammerspoon.d.ts @@ -3745,6 +3745,112 @@ if you only want to temporarily remove the item without freeing it. } +/** + * Control and inspect the mouse pointer and attached mouse devices. +## Position +All coordinates use **Hammerspoon screen coordinates**: `(0, 0)` is at the top-left +of the primary display and `y` increases downward. +```js +const pos = hs.mouse.absolutePosition() +console.log("Mouse at " + pos.x + ", " + pos.y) + +hs.mouse.setAbsolutePosition(100, 200) +``` +## Device info +```js +console.log("Mice: " + hs.mouse.count()) +hs.mouse.names().forEach(n => console.log(n)) +``` +## Cursor +```js +console.log(hs.mouse.currentCursorType()) // e.g. "arrow" +console.log(hs.mouse.scrollDirection()) // "natural" or "normal" +``` + */ +declare namespace hs.mouse { + /** + * Returns the current mouse pointer position in Hammerspoon screen coordinates. +Hammerspoon coordinates have `(0, 0)` at the top-left of the primary display, +with `y` increasing downward. + * @returns An object with `x` and `y` number properties. + */ + function absolutePosition(): Record; + + /** + * Moves the mouse pointer to the specified absolute position in Hammerspoon screen coordinates. + * @param x Horizontal position; `0` is the left edge of the primary display. + * @param y Vertical position; `0` is the top edge of the primary display. + */ + function setAbsolutePosition(x: number, y: number): void; + + /** + * Returns the mouse pointer position relative to the screen it is currently on. +The returned coordinates have `(0, 0)` at the top-left corner of the screen +that the cursor is on. + * @returns An object with `x` and `y` number properties, or `null` if no screen can be determined. + */ + function getRelativePosition(): Record | null; + + /** + * Moves the mouse pointer to a position relative to the screen it is currently on. + * @param x Horizontal offset from the current screen's left edge. + * @param y Vertical offset from the current screen's top edge. + */ + function setRelativePosition(x: number, y: number): void; + + /** + * Returns the screen that the mouse pointer is currently on. + * @returns An HSScreen object for the display containing the cursor, or `null` if none can be determined. + */ + function getCurrentScreen(): HSScreen | null; + + /** + * Returns the number of mouse devices currently attached to the system. + * @param includeInternal When `true`, built-in pointing devices (e.g. the MacBook built-in trackpad) are included. Defaults to `false`. + * @returns The number of attached mouse devices. + */ + function count(includeInternal: boolean): number; + + /** + * Returns the product names of all mouse devices currently attached to the system. + * @param includeInternal When `true`, built-in pointing devices are included. Defaults to `false`. + * @returns An array of product name strings. + */ + function names(includeInternal: boolean): string[]; + + /** + * Returns the current mouse tracking speed (acceleration level). +Values range from `-1.0` (system default, acceleration disabled) to `3.0` (maximum acceleration). +Returns `-1.0` if the value cannot be read. + * @returns The current tracking speed as a number. + */ + function trackingSpeed(): number; + + /** + * Sets the mouse tracking speed (acceleration level). +The change takes effect immediately for the current login session and is also persisted +to preferences so it survives a restart. Values outside the valid range or non-finite +values are rejected with a warning and no change is made. + * @param speed Desired tracking speed in the range `-1.0` to `3.0`. + */ + function setTrackingSpeed(speed: number): void; + + /** + * Returns the current scroll wheel direction setting. + * @returns `"natural"` if content scrolls in the same direction as the finger/wheel movement (macOS default), or `"normal"` for the traditional direction. + */ + function scrollDirection(): string; + + /** + * Returns the name of the cursor type currently set by this application. +has the keyboard focus, the visible system cursor may differ. + * @remarks This reflects the cursor set by the Hammerspoon process. If another application + * @returns A string such as `"arrow"`, `"iBeam"`, `"crosshair"`, `"pointingHand"`, + */ + function currentCursorType(): string; + +} + /** * Module for inspecting network interfaces, resolving hostnames, and reading system configuration */ diff --git a/docs/js/html/hs.mouse.html b/docs/js/html/hs.mouse.html new file mode 100644 index 00000000..71758044 --- /dev/null +++ b/docs/js/html/hs.mouse.html @@ -0,0 +1,443 @@ + + + + + + hs.mouse - Hammerspoon 2 API + + + + + +
+
+ + API Docs +
+
+
+ + + +
+
+ +
+ +
+ + + + +
+ + + +

Control and inspect the mouse pointer and attached mouse devices.

+

Position

+

All coordinates use Hammerspoon screen coordinates: (0, 0) is at the top-left +of the primary display and y increases downward.

+
const pos = hs.mouse.absolutePosition()
+console.log("Mouse at " + pos.x + ", " + pos.y)
+
+hs.mouse.setAbsolutePosition(100, 200)
+
+

Device info

+
console.log("Mice: " + hs.mouse.count())
+hs.mouse.names().forEach(n => console.log(n))
+
+

Cursor

+
console.log(hs.mouse.currentCursorType())   // e.g. "arrow"
+console.log(hs.mouse.scrollDirection())      // "natural" or "normal"
+
+
+ + +

Properties

+

This module has no properties.

+ +

Methods

+
+

hs.mouse.absolutePosition() -> {[key: string]: number}

+ +
Returns the current mouse pointer position in Hammerspoon screen coordinates. +Hammerspoon coordinates have `(0, 0)` at the top-left of the primary display, +with `y` increasing downward.
+ + +
hs.mouse.absolutePosition() -> {[key: string]: number}
+ + + +
{[key: string]: number}
+
An object with `x` and `y` number properties.
+ + + +
const pos = hs.mouse.absolutePosition()
+console.log("x=" + pos.x + " y=" + pos.y)
+ + +
+
+

hs.mouse.setAbsolutePosition(x, y) -> None

+ +
Moves the mouse pointer to the specified absolute position in Hammerspoon screen coordinates.
+ + +
hs.mouse.setAbsolutePosition(x, y) -> None
+ + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xnumberHorizontal position; `0` is the left edge of the primary display.
ynumberVertical position; `0` is the top edge of the primary display.
+ + +
None
+ + + +
hs.mouse.setAbsolutePosition(100, 200)
+ + +
+
+

hs.mouse.getRelativePosition() -> [String: Double]

+ +
Returns the mouse pointer position relative to the screen it is currently on. +The returned coordinates have `(0, 0)` at the top-left corner of the screen +that the cursor is on.
+ + +
hs.mouse.getRelativePosition() -> [String: Double]
+ + + +
[String: Double]
+
An object with `x` and `y` number properties, or `null` if no screen can be determined.
+ + + +
const rel = hs.mouse.getRelativePosition()
+if (rel) console.log("x=" + rel.x + " y=" + rel.y)
+ + +
+
+

hs.mouse.setRelativePosition(x, y) -> None

+ +
Moves the mouse pointer to a position relative to the screen it is currently on.
+ + +
hs.mouse.setRelativePosition(x, y) -> None
+ + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xnumberHorizontal offset from the current screen's left edge.
ynumberVertical offset from the current screen's top edge.
+ + +
None
+ + + +
hs.mouse.setRelativePosition(0, 0)  // move to top-left of current screen
+ + +
+
+

hs.mouse.getCurrentScreen() -> HSScreen

+ +
Returns the screen that the mouse pointer is currently on.
+ + +
hs.mouse.getCurrentScreen() -> HSScreen
+ + + +
HSScreen
+
An HSScreen object for the display containing the cursor, or `null` if none can be determined.
+ + + +
const s = hs.mouse.getCurrentScreen()
+if (s) console.log("Mouse is on: " + s.name)
+ + +
+
+

hs.mouse.count(includeInternal) -> number

+ +
Returns the number of mouse devices currently attached to the system.
+ + +
hs.mouse.count(includeInternal) -> number
+ + + + + + + + + + + + + + + + + +
NameTypeDescription
includeInternalbooleanWhen `true`, built-in pointing devices (e.g. the MacBook built-in trackpad) are included. Defaults to `false`.
+ + +
number
+
The number of attached mouse devices.
+ + + +
console.log("External mice: " + hs.mouse.count())
+console.log("All pointing devices: " + hs.mouse.count(true))
+ + +
+
+

hs.mouse.names(includeInternal) -> string[]

+ +
Returns the product names of all mouse devices currently attached to the system.
+ + +
hs.mouse.names(includeInternal) -> string[]
+ + + + + + + + + + + + + + + + + +
NameTypeDescription
includeInternalbooleanWhen `true`, built-in pointing devices are included. Defaults to `false`.
+ + +
string[]
+
An array of product name strings.
+ + + +
hs.mouse.names().forEach(n => console.log(n))
+ + +
+
+

hs.mouse.trackingSpeed() -> number

+ +
Returns the current mouse tracking speed (acceleration level). +Values range from `-1.0` (system default, acceleration disabled) to `3.0` (maximum acceleration). +Returns `-1.0` if the value cannot be read.
+ + +
hs.mouse.trackingSpeed() -> number
+ + + +
number
+
The current tracking speed as a number.
+ + + +
console.log("Tracking speed: " + hs.mouse.trackingSpeed())
+ + +
+
+

hs.mouse.setTrackingSpeed(speed) -> None

+ +
Sets the mouse tracking speed (acceleration level). +The change takes effect immediately for the current login session and is also persisted +to preferences so it survives a restart. Values outside the valid range or non-finite +values are rejected with a warning and no change is made.
+ + +
hs.mouse.setTrackingSpeed(speed) -> None
+ + + + + + + + + + + + + + + + + +
NameTypeDescription
speednumberDesired tracking speed in the range `-1.0` to `3.0`.
+ + +
None
+ + + +
hs.mouse.setTrackingSpeed(1.5)
+ + +
+
+

hs.mouse.scrollDirection() -> string

+ +
Returns the current scroll wheel direction setting.
+ + +
hs.mouse.scrollDirection() -> string
+ + + +
string
+
`"natural"` if content scrolls in the same direction as the finger/wheel movement (macOS default), or `"normal"` for the traditional direction.
+ + + +
console.log(hs.mouse.scrollDirection())
+ + +
+
+

hs.mouse.currentCursorType() -> string

+ +
Returns the name of the cursor type currently set by this application. +has the keyboard focus, the visible system cursor may differ.
+ + +
hs.mouse.currentCursorType() -> string
+ + + +
string
+
A string such as `"arrow"`, `"iBeam"`, `"crosshair"`, `"pointingHand"`,
+ + +
This reflects the cursor set by the Hammerspoon process. If another application
+ + +
console.log(hs.mouse.currentCursorType())
+ + +
+
+ + + +
+ + + + + diff --git a/docs/js/html/index.html b/docs/js/html/index.html index e8f63532..3aadc3a2 100644 --- a/docs/js/html/index.html +++ b/docs/js/html/index.html @@ -144,6 +144,10 @@

hs.location

hs.menubar

protocols · functions

+ +

hs.mouse

+

protocols · functions

+

hs.network

protocols · functions

diff --git a/docs/js/html/script.js b/docs/js/html/script.js index 0b3fe0e8..ee4f6884 100644 --- a/docs/js/html/script.js +++ b/docs/js/html/script.js @@ -81,6 +81,10 @@ const navigationData = { "name": "hs.menubar", "url": "hs.menubar.html" }, + { + "name": "hs.mouse", + "url": "hs.mouse.html" + }, { "name": "hs.network", "url": "hs.network.html" @@ -337,7 +341,7 @@ const navigationData = { } ] }; -const searchIndex = [{"fullName":"console","description":"These functions are provided to maintain convenience with the console.log() function present in many JavaScript instances.","url":"console.html","kind":"module"},{"fullName":"console.log(message)","description":"Log a message to the Hammerspoon Log Window","url":"console.html#log","kind":"method"},{"fullName":"console.error(message)","description":"Log an error to the Hammerspoon Log Window","url":"console.html#error","kind":"method"},{"fullName":"console.warn(message)","description":"Log a warning to the Hammerspoon Log WIndow","url":"console.html#warn","kind":"method"},{"fullName":"console.info(message)","description":"Log an informational message to the Hammerspoon Log Window","url":"console.html#info","kind":"method"},{"fullName":"console.debug(message)","description":"Log a debug message to the Hammerspoon Log Window","url":"console.html#debug","kind":"method"},{"fullName":"hs","description":"","url":"hs.html","kind":"module"},{"fullName":"hs.reload()","description":"Destroy the current JavaScript runtime and start a new one, loading all configuration from disk again","url":"hs.html#reload","kind":"method"},{"fullName":"hs.collectGarbage()","description":"Force garbage collection of JavaScript objects that no longer have any references","url":"hs.html#collectGarbage","kind":"method"},{"fullName":"hs.openConsole()","description":"Open the Hammerspoon Console window","url":"hs.html#openConsole","kind":"method"},{"fullName":"hs.closeConsole()","description":"Close the Hammerspoon Console window","url":"hs.html#closeConsole","kind":"method"},{"fullName":"hs.clearConsole()","description":"Clear the Hammerspoon Console log","url":"hs.html#clearConsole","kind":"method"},{"fullName":"hs.appinfo","description":"Module for accessing information about the Hammerspoon application itself","url":"hs.appinfo.html","kind":"module"},{"fullName":"hs.appinfo.appName","description":"The application's internal name (e.g., \"Hammerspoon 2\")","url":"hs.appinfo.html#appName","kind":"property"},{"fullName":"hs.appinfo.displayName","description":"The application's display name shown to users","url":"hs.appinfo.html#displayName","kind":"property"},{"fullName":"hs.appinfo.version","description":"The application's version string (e.g., \"2.0.0\")","url":"hs.appinfo.html#version","kind":"property"},{"fullName":"hs.appinfo.build","description":"The application's build number","url":"hs.appinfo.html#build","kind":"property"},{"fullName":"hs.appinfo.minimumOSVersion","description":"The minimum macOS version required to run this application","url":"hs.appinfo.html#minimumOSVersion","kind":"property"},{"fullName":"hs.appinfo.copyrightNotice","description":"The copyright notice for this application","url":"hs.appinfo.html#copyrightNotice","kind":"property"},{"fullName":"hs.appinfo.bundleIdentifier","description":"The application's bundle identifier (e.g., \"com.hammerspoon.Hammerspoon-2\")","url":"hs.appinfo.html#bundleIdentifier","kind":"property"},{"fullName":"hs.appinfo.bundlePath","description":"The filesystem path to the application bundle","url":"hs.appinfo.html#bundlePath","kind":"property"},{"fullName":"hs.appinfo.resourcePath","description":"The filesystem path to the application's resource directory","url":"hs.appinfo.html#resourcePath","kind":"property"},{"fullName":"hs.appinfo.configPath","description":"The filesystem path to the main Hammerspoon 2 configuration file","url":"hs.appinfo.html#configPath","kind":"property"},{"fullName":"hs.appinfo.configDir","description":"The filesystem path to the directory Hammerspoon 2 loaded its config from","url":"hs.appinfo.html#configDir","kind":"property"},{"fullName":"hs.application","description":"Module for interacting with applications","url":"hs.application.html","kind":"module"},{"fullName":"hs.application.runningApplications()","description":"Fetch all running applications","url":"hs.application.html#runningApplications","kind":"method"},{"fullName":"hs.application.matchingName(name)","description":"Fetch the first running application that matches a name","url":"hs.application.html#matchingName","kind":"method"},{"fullName":"hs.application.matchingBundleID(bundleID)","description":"Fetch the first running application that matches a Bundle ID","url":"hs.application.html#matchingBundleID","kind":"method"},{"fullName":"hs.application.fromPID(pid)","description":"Fetch the running application that matches a POSIX PID","url":"hs.application.html#fromPID","kind":"method"},{"fullName":"hs.application.frontmost()","description":"Fetch the currently focused application","url":"hs.application.html#frontmost","kind":"method"},{"fullName":"hs.application.menuBarOwner()","description":"Fetch the application which currently owns the menu bar","url":"hs.application.html#menuBarOwner","kind":"method"},{"fullName":"hs.application.pathForBundleID(bundleID)","description":"Fetch the filesystem path for an application","url":"hs.application.html#pathForBundleID","kind":"method"},{"fullName":"hs.application.pathsForBundleID(bundleID)","description":"Fetch filesystem paths for an application","url":"hs.application.html#pathsForBundleID","kind":"method"},{"fullName":"hs.application.pathForFileType(fileType)","description":"Fetch filesystem path for an application able to open a given file type","url":"hs.application.html#pathForFileType","kind":"method"},{"fullName":"hs.application.pathsForFileType(fileType)","description":"Fetch filesystem paths for applications able to open a given file type","url":"hs.application.html#pathsForFileType","kind":"method"},{"fullName":"hs.application.launchOrFocus(bundleID)","description":"Launch an application, or give it focus if it's already running","url":"hs.application.html#launchOrFocus","kind":"method"},{"fullName":"hs.application.addWatcher(listener)","description":"Create a watcher for application events","url":"hs.application.html#addWatcher","kind":"method"},{"fullName":"hs.application.removeWatcher(listener)","description":"Remove a watcher for application events","url":"hs.application.html#removeWatcher","kind":"method"},{"fullName":"hs.audiodevice","description":"Module for discovering and controlling audio devices.","url":"hs.audiodevice.html","kind":"module"},{"fullName":"hs.audiodevice.all()","description":"All audio devices attached to the system.","url":"hs.audiodevice.html#all","kind":"method"},{"fullName":"hs.audiodevice.allOutputDevices()","description":"All audio devices that have at least one output stream.","url":"hs.audiodevice.html#allOutputDevices","kind":"method"},{"fullName":"hs.audiodevice.allInputDevices()","description":"All audio devices that have at least one input stream.","url":"hs.audiodevice.html#allInputDevices","kind":"method"},{"fullName":"hs.audiodevice.defaultOutputDevice()","description":"The current system default output device.","url":"hs.audiodevice.html#defaultOutputDevice","kind":"method"},{"fullName":"hs.audiodevice.defaultInputDevice()","description":"The current system default input device.","url":"hs.audiodevice.html#defaultInputDevice","kind":"method"},{"fullName":"hs.audiodevice.defaultEffectDevice()","description":"The current system alert sound device.","url":"hs.audiodevice.html#defaultEffectDevice","kind":"method"},{"fullName":"hs.audiodevice.findDeviceByName(name)","description":"Find the first audio device whose name matches the given string.","url":"hs.audiodevice.html#findDeviceByName","kind":"method"},{"fullName":"hs.audiodevice.findDeviceByUID(uid)","description":"Find the audio device with the given unique identifier.","url":"hs.audiodevice.html#findDeviceByUID","kind":"method"},{"fullName":"hs.audiodevice.addWatcher(listener)","description":"Register a listener for all system-level audio configuration events.","url":"hs.audiodevice.html#addWatcher","kind":"method"},{"fullName":"hs.audiodevice.removeWatcher(listener)","description":"Remove a previously registered system-level listener.","url":"hs.audiodevice.html#removeWatcher","kind":"method"},{"fullName":"hs.audiodevice._makeDeviceEmitter()","description":"SKIP_DOCS","url":"hs.audiodevice.html#_makeDeviceEmitter","kind":"method"},{"fullName":"hs.ax","description":"# Accessibility API Module","url":"hs.ax.html","kind":"module"},{"fullName":"hs.ax.notificationTypes","description":"A dictionary containing all of the notification types that can be used with hs.ax.addWatcher()","url":"hs.ax.html#notificationTypes","kind":"property"},{"fullName":"hs.ax.systemWideElement()","description":"Get the system-wide accessibility element","url":"hs.ax.html#systemWideElement","kind":"method"},{"fullName":"hs.ax.applicationElement(element)","description":"Get the accessibility element for an application","url":"hs.ax.html#applicationElement","kind":"method"},{"fullName":"hs.ax.windowElement(window)","description":"Get the accessibility element for a window","url":"hs.ax.html#windowElement","kind":"method"},{"fullName":"hs.ax.elementAtPoint(point)","description":"Get the accessibility element at the specific screen position","url":"hs.ax.html#elementAtPoint","kind":"method"},{"fullName":"hs.ax.addWatcher(application, notification, listener)","description":"Add a watcher for application AX events","url":"hs.ax.html#addWatcher","kind":"method"},{"fullName":"hs.ax.removeWatcher(application, notification, listener)","description":"Remove a watcher for application AX events","url":"hs.ax.html#removeWatcher","kind":"method"},{"fullName":"hs.ax.focusedElement()","description":"Fetch the focused UI element","url":"hs.ax.html#focusedElement","kind":"method"},{"fullName":"hs.ax.findByRole(role, parent)","description":"Find AX elements matching a given role","url":"hs.ax.html#findByRole","kind":"method"},{"fullName":"hs.ax.findByTitle(title, parent)","description":"Find AX elements whose title contains a given string","url":"hs.ax.html#findByTitle","kind":"method"},{"fullName":"hs.ax.printHierarchy(element, maxDepth)","description":"Print the accessibility hierarchy of an element to the Console","url":"hs.ax.html#printHierarchy","kind":"method"},{"fullName":"hs.bonjour","description":"Discover and publish Bonjour (mDNS / Zeroconf) network services.","url":"hs.bonjour.html","kind":"module"},{"fullName":"hs.bonjour.serviceTypes","description":"A frozen object mapping short service-type names to their mDNS strings. Populated by the JavaScript enhancement layer.","url":"hs.bonjour.html#serviceTypes","kind":"property"},{"fullName":"hs.bonjour.createSearch()","description":"Creates a new Bonjour search for discovering services or domains. Call one of the find… methods on the returned search to start discovering. Remove it with removeSearch() when finished.","url":"hs.bonjour.html#createSearch","kind":"method"},{"fullName":"hs.bonjour.removeSearch(search)","description":"Stops and removes a previously created search.","url":"hs.bonjour.html#removeSearch","kind":"method"},{"fullName":"hs.bonjour.advertise(name, type, port, domain, callback)","description":"Starts advertising a local service on the network. If domain is omitted or not a string, it defaults to \"local.\". If the 4th argument is a function, it is used as the callback and domain defaults to \"local.\".","url":"hs.bonjour.html#advertise","kind":"method"},{"fullName":"hs.bonjour.stopAdvertising(name, type)","description":"Stops advertising a service previously started with advertise().","url":"hs.bonjour.html#stopAdvertising","kind":"method"},{"fullName":"hs.bonjour.networkServices(timeout)","description":"Returns a Promise that resolves to an array of service-type strings currently advertised on the local network. Internally searches for _services._dns-sd._udp. services, collects results for up to timeout seconds (or until the browser signals no more results), then resolves.","url":"hs.bonjour.html#networkServices","kind":"method"},{"fullName":"hs.camera","description":"Module for discovering and interacting with camera devices.","url":"hs.camera.html","kind":"module"},{"fullName":"hs.camera.all()","description":"All video camera devices currently connected to the system.","url":"hs.camera.html#all","kind":"method"},{"fullName":"hs.camera.findByName(name)","description":"Find the first camera whose name matches the given string.","url":"hs.camera.html#findByName","kind":"method"},{"fullName":"hs.camera.findByUID(uid)","description":"Find the camera with the given unique identifier.","url":"hs.camera.html#findByUID","kind":"method"},{"fullName":"hs.camera.addWatcher(listener)","description":"Register a listener for camera device connect/disconnect events.","url":"hs.camera.html#addWatcher","kind":"method"},{"fullName":"hs.camera.removeWatcher(listener)","description":"Remove a previously registered module-level event listener.","url":"hs.camera.html#removeWatcher","kind":"method"},{"fullName":"hs.camera._makeCameraEmitter()","description":"SKIP_DOCS","url":"hs.camera.html#_makeCameraEmitter","kind":"method"},{"fullName":"hs.chooser","description":"# hs.chooser","url":"hs.chooser.html","kind":"module"},{"fullName":"hs.chooser.create()","description":"Create a new chooser.","url":"hs.chooser.html#create","kind":"method"},{"fullName":"hs.docs","description":"# hs.docs","url":"hs.docs.html","kind":"module"},{"fullName":"hs.docs.show(moduleName, showTS)","description":"Open the Hammerspoon 2 API documentation in a new window","url":"hs.docs.html#show","kind":"method"},{"fullName":"hs.docs.get(identifier)","description":"Return documentation for a module, method, or property","url":"hs.docs.html#get","kind":"method"},{"fullName":"hs.docs.jsDocsPath()","description":"Return the filesystem path to the bundled JS documentation directory","url":"hs.docs.html#jsDocsPath","kind":"method"},{"fullName":"hs.docs.tsDocsPath()","description":"Return the filesystem path to the bundled TypeScript documentation directory","url":"hs.docs.html#tsDocsPath","kind":"method"},{"fullName":"hs.docs.apiJSON()","description":"Return the contents of the bundled api.json file","url":"hs.docs.html#apiJSON","kind":"method"},{"fullName":"hs.eventtap","description":"Monitor and synthesise macOS input events: keyboard, mouse, and scroll wheel.","url":"hs.eventtap.html","kind":"module"},{"fullName":"hs.eventtap.eventTypes","description":"A dictionary mapping event type names to their numeric values. Pass values from this dictionary to addWatcher() to specify which events to monitor.","url":"hs.eventtap.html#eventTypes","kind":"property"},{"fullName":"hs.eventtap.modifierFlags","description":"A dictionary mapping modifier key names to their bitmask values for use with rawFlags. Includes generic names (cmd, shift, alt, ctrl) and side-specific names (leftCmd, rightCmd, leftShift, rightShift, leftAlt, rightAlt, leftCtrl, rightCtrl) for distinguishing physical keys.","url":"hs.eventtap.html#modifierFlags","kind":"property"},{"fullName":"hs.eventtap.consume","description":"Return this from an event tap callback to suppress the event (prevent other apps from receiving it).","url":"hs.eventtap.html#consume","kind":"property"},{"fullName":"hs.eventtap.emit","description":"Return this from an event tap callback to allow the event to pass through to other applications.","url":"hs.eventtap.html#emit","kind":"property"},{"fullName":"hs.eventtap.addWatcher(types, callback, listenOnly)","description":"Create an event tap that calls a function for matching events. Call .start() to activate it. The callback receives an HSEventTapEvent. For modify taps (listenOnly omitted or false), return hs.eventtap.consume (false) to suppress the event or hs.eventtap.emit (true) to pass it through. For listen-only taps the callback's return value is ignored — events are always delivered to other applications. Requires Accessibility permission.","url":"hs.eventtap.html#addWatcher","kind":"method"},{"fullName":"hs.eventtap.removeWatcher(tap)","description":"Stop and remove a previously created watcher","url":"hs.eventtap.html#removeWatcher","kind":"method"},{"fullName":"hs.eventtap.makeKeyEvent(key, isDown)","description":"Create a keyboard event","url":"hs.eventtap.html#makeKeyEvent","kind":"method"},{"fullName":"hs.eventtap.makeKeyEventWithCode(keyCode, isDown)","description":"Create a keyboard event using a raw key code","url":"hs.eventtap.html#makeKeyEventWithCode","kind":"method"},{"fullName":"hs.eventtap.makeMouseEvent(type, x, y, button)","description":"Create a mouse event at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin of the primary display, y increases downward), matching the values returned by hs.screen.","url":"hs.eventtap.html#makeMouseEvent","kind":"method"},{"fullName":"hs.eventtap.makeScrollWheelEvent(deltaX, deltaY, x, y)","description":"Create a scroll wheel event at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#makeScrollWheelEvent","kind":"method"},{"fullName":"hs.eventtap.keyStroke(mods, key)","description":"Send a key down and key up event with optional modifier keys. A 50 ms pause is inserted between the key-down and key-up events to improve compatibility with applications that miss very fast synthetic keystrokes.","url":"hs.eventtap.html#keyStroke","kind":"method"},{"fullName":"hs.eventtap.keyStrokes(text)","description":"Type a string of characters as individual key events. A 50 ms pause is inserted between each key-down and key-up event.","url":"hs.eventtap.html#keyStrokes","kind":"method"},{"fullName":"hs.eventtap.leftClick(x, y)","description":"Post a left mouse button click at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#leftClick","kind":"method"},{"fullName":"hs.eventtap.rightClick(x, y)","description":"Post a right mouse button click at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#rightClick","kind":"method"},{"fullName":"hs.eventtap.doubleLeftClick(x, y)","description":"Post a left mouse button double-click at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#doubleLeftClick","kind":"method"},{"fullName":"hs.eventtap.middleClick(x, y)","description":"Post a middle mouse button click at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#middleClick","kind":"method"},{"fullName":"hs.eventtap.scrollWheel(deltaX, deltaY, x, y)","description":"Post a scroll wheel event at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#scrollWheel","kind":"method"},{"fullName":"hs.eventtap.currentModifiers()","description":"Returns the currently held modifier keys","url":"hs.eventtap.html#currentModifiers","kind":"method"},{"fullName":"hs.eventtap.checkMouseButtons()","description":"Returns the currently pressed mouse buttons","url":"hs.eventtap.html#checkMouseButtons","kind":"method"},{"fullName":"hs.eventtap.mouseLocation()","description":"Returns the current mouse cursor position in Hammerspoon screen coordinates (top-left origin of primary display, y increases downward, matching hs.screen).","url":"hs.eventtap.html#mouseLocation","kind":"method"},{"fullName":"hs.eventtap.doubleClickInterval()","description":"Returns the system double-click interval in seconds","url":"hs.eventtap.html#doubleClickInterval","kind":"method"},{"fullName":"hs.eventtap.keyRepeatDelay()","description":"Returns the system key repeat delay in seconds","url":"hs.eventtap.html#keyRepeatDelay","kind":"method"},{"fullName":"hs.eventtap.keyRepeatInterval()","description":"Returns the system key repeat interval in seconds","url":"hs.eventtap.html#keyRepeatInterval","kind":"method"},{"fullName":"hs.eventtap.bindHotkey(mods, key, callbackPressed, callbackReleased)","description":"Bind a keyboard shortcut using an event tap. Unlike hs.hotkey.bind(), this supports the fn modifier and left/right modifier key distinction (e.g. leftCmd, rightAlt). The hotkey is active immediately and consumes (suppresses) the key events. It's important to note that this a much heavier-weight tool than hs.hotkey - every single key you press will be examined by Hammerspoon to see if it matches one of the EventTap hotkeys (where hs.hotkey relies on macOS to efficiently deliver only matching keypresses). Please consider this when choosing to use hs.eventtap for hotkeys. Requires Accessibility permission. ctrl, fn) and side-specific names (leftCmd, rightCmd, leftAlt, rightAlt, leftCtrl, rightCtrl, leftShift, rightShift).","url":"hs.eventtap.html#bindHotkey","kind":"method"},{"fullName":"hs.eventtap.removeHotkey(hotkey)","description":"Remove a previously bound hotkey and stop it from firing","url":"hs.eventtap.html#removeHotkey","kind":"method"},{"fullName":"hs.fs","description":"Module for filesystem operations.","url":"hs.fs.html","kind":"module"},{"fullName":"hs.fs.read(path, offset, length)","description":"Read part or all of a file as a UTF-8 string.","url":"hs.fs.html#read","kind":"method"},{"fullName":"hs.fs.readLines(path, callback)","description":"Read a file line-by-line, invoking a callback for each line. Lines are delivered with newline characters stripped. Both \\n and \\r\\n line endings are handled.","url":"hs.fs.html#readLines","kind":"method"},{"fullName":"hs.fs.write(path, content, inPlace)","description":"Write a UTF-8 string to a file, creating it or overwriting any existing content. Intermediate directories are not created automatically; use mkdir first if needed.","url":"hs.fs.html#write","kind":"method"},{"fullName":"hs.fs.append(path, content)","description":"Append a UTF-8 string to a file, creating it if it does not exist.","url":"hs.fs.html#append","kind":"method"},{"fullName":"hs.fs.exists(path)","description":"Determine if a filesystem object exists at the given path Unlike isFile and isDirectory, this follows symlinks.","url":"hs.fs.html#exists","kind":"method"},{"fullName":"hs.fs.isFile(path)","description":"Determine if a file exists at the given path This does not follow symlinks; a symlink pointing at a file returns false.","url":"hs.fs.html#isFile","kind":"method"},{"fullName":"hs.fs.isDirectory(path)","description":"Determine if a directory exists at the given path This does not follow symlinks; a symlink pointing at a directory returns false.","url":"hs.fs.html#isDirectory","kind":"method"},{"fullName":"hs.fs.isSymlink(path)","description":"Determine if a symlink exists at the given path","url":"hs.fs.html#isSymlink","kind":"method"},{"fullName":"hs.fs.isReadable(path)","description":"Determine if a given filesystem path is readable","url":"hs.fs.html#isReadable","kind":"method"},{"fullName":"hs.fs.isWritable(path)","description":"Determine if a given filesystem path is writable","url":"hs.fs.html#isWritable","kind":"method"},{"fullName":"hs.fs.copy(source, destination)","description":"Copy a file or directory to a new location. The destination must not already exist. If source is a directory, its entire contents are copied recursively.","url":"hs.fs.html#copy","kind":"method"},{"fullName":"hs.fs.move(source, destination)","description":"Move (rename) a file or directory. The destination must not already exist.","url":"hs.fs.html#move","kind":"method"},{"fullName":"hs.fs.deletePath(path)","description":"Delete a file or directory at the given path. Directories are removed recursively. To remove only an empty directory, use rmdir instead.","url":"hs.fs.html#deletePath","kind":"method"},{"fullName":"hs.fs.list(path)","description":"List the immediate contents of a directory. Returns bare filenames (not full paths), sorted alphabetically. The . and .. entries are never included.","url":"hs.fs.html#list","kind":"method"},{"fullName":"hs.fs.listRecursive(path)","description":"Recursively list all entries under a directory. Returns paths relative to path, sorted alphabetically.","url":"hs.fs.html#listRecursive","kind":"method"},{"fullName":"hs.fs.mkdir(path)","description":"Create a directory, including all necessary intermediate directories. Succeeds silently if the directory already exists.","url":"hs.fs.html#mkdir","kind":"method"},{"fullName":"hs.fs.rmdir(path)","description":"Remove an empty directory. Fails if the directory is not empty. Use deletePath to remove a non-empty directory recursively.","url":"hs.fs.html#rmdir","kind":"method"},{"fullName":"hs.fs.currentDir()","description":"Returns the current working directory of the process.","url":"hs.fs.html#currentDir","kind":"method"},{"fullName":"hs.fs.chdir(path)","description":"Change the current working directory of the process.","url":"hs.fs.html#chdir","kind":"method"},{"fullName":"hs.fs.pathToAbsolute(path)","description":"Resolve a path to its absolute, canonical form. Expands ~, resolves . and .., and follows all symbolic links. Returns null if any component of the path does not exist.","url":"hs.fs.html#pathToAbsolute","kind":"method"},{"fullName":"hs.fs.displayName(path)","description":"Return the localised display name for a file or directory as shown by Finder. For example, /Library appears as \"Library\" in Finder even though its on-disk name is the same.","url":"hs.fs.html#displayName","kind":"method"},{"fullName":"hs.fs.temporaryDirectory()","description":"Returns the temporary directory for the current user.","url":"hs.fs.html#temporaryDirectory","kind":"method"},{"fullName":"hs.fs.homeDirectory()","description":"Returns the home directory for the current user.","url":"hs.fs.html#homeDirectory","kind":"method"},{"fullName":"hs.fs.urlFromPath(path)","description":"Returns a file:// URL string for the given path.","url":"hs.fs.html#urlFromPath","kind":"method"},{"fullName":"hs.fs.attributes(path)","description":"Get metadata attributes for a file or directory. Does not follow symbolic links. Use isSymlink to detect links before calling this if needed.","url":"hs.fs.html#attributes","kind":"method"},{"fullName":"hs.fs.touch(path)","description":"Update the modification timestamp of a file to the current time. Creates the file if it does not exist (equivalent to the POSIX touch command).","url":"hs.fs.html#touch","kind":"method"},{"fullName":"hs.fs.link(source, destination)","description":"Create a hard link at destination pointing at source. Both paths must be on the same filesystem volume.","url":"hs.fs.html#link","kind":"method"},{"fullName":"hs.fs.symlink(source, destination)","description":"Create a symbolic link at destination pointing at source. Unlike hard links, symlinks may cross filesystem boundaries and may point to paths that do not yet exist.","url":"hs.fs.html#symlink","kind":"method"},{"fullName":"hs.fs.readlink(path)","description":"Read the target of a symbolic link without resolving it.","url":"hs.fs.html#readlink","kind":"method"},{"fullName":"hs.fs.tags(path)","description":"Get the Finder tags assigned to a file or directory.","url":"hs.fs.html#tags","kind":"method"},{"fullName":"hs.fs.fileUTI(path)","description":"Replace all Finder tags on a file or directory. This function is only available on macOS Tahoe (26) or later.","url":"hs.fs.html#fileUTI","kind":"method"},{"fullName":"hs.fs.pathToBookmark(path)","description":"Encode a file path as a persistent bookmark that survives file moves and renames. The returned string is base64-encoded bookmark data that can be stored and later resolved with pathFromBookmark.","url":"hs.fs.html#pathToBookmark","kind":"method"},{"fullName":"hs.fs.pathFromBookmark(data)","description":"Resolve a base64-encoded bookmark back to a file path.","url":"hs.fs.html#pathFromBookmark","kind":"method"},{"fullName":"hs.fs.volumes(showHidden)","description":"Return information about all currently mounted filesystem volumes.","url":"hs.fs.html#volumes","kind":"method"},{"fullName":"hs.fs.ejectVolume(path)","description":"Unmount and eject the volume at the given path.","url":"hs.fs.html#ejectVolume","kind":"method"},{"fullName":"hs.fs.addVolumeWatcher()","description":"Create a new volume event watcher. Call setCallback() and start() on the returned object to begin receiving volume mount/unmount/rename events.","url":"hs.fs.html#addVolumeWatcher","kind":"method"},{"fullName":"hs.fs.removeVolumeWatcher(watcher)","description":"Stop and destroy a volume watcher previously created with addVolumeWatcher.","url":"hs.fs.html#removeVolumeWatcher","kind":"method"},{"fullName":"hs.fs.xattrGet(path, attribute, options, position)","description":"Get the value of an extended attribute for a file or directory. Attribute values are returned as ISO Latin-1 encoded strings so that arbitrary byte sequences are represented without loss. ASCII text attribute values appear readable as-is.","url":"hs.fs.html#xattrGet","kind":"method"},{"fullName":"hs.fs.xattrList(path, options)","description":"List all extended attributes defined for a file or directory.","url":"hs.fs.html#xattrList","kind":"method"},{"fullName":"hs.fs.xattrSet(path, attribute, value, options, position)","description":"Set the value of an extended attribute for a file or directory. The value is written as ISO Latin-1 bytes, providing a lossless round-trip with xattrGet. Plain ASCII strings work directly without any encoding.","url":"hs.fs.html#xattrSet","kind":"method"},{"fullName":"hs.fs.xattrRemove(path, attribute, options)","description":"Remove an extended attribute from a file or directory.","url":"hs.fs.html#xattrRemove","kind":"method"},{"fullName":"hs.hash","description":"Module for hashing and encoding operations","url":"hs.hash.html","kind":"module"},{"fullName":"hs.hash.base64Encode(data)","description":"Encode a string to base64","url":"hs.hash.html#base64Encode","kind":"method"},{"fullName":"hs.hash.base64Decode(data)","description":"Decode a base64 string","url":"hs.hash.html#base64Decode","kind":"method"},{"fullName":"hs.hash.md5(data)","description":"Generate MD5 hash of a string","url":"hs.hash.html#md5","kind":"method"},{"fullName":"hs.hash.sha1(data)","description":"Generate SHA1 hash of a string","url":"hs.hash.html#sha1","kind":"method"},{"fullName":"hs.hash.sha256(data)","description":"Generate SHA256 hash of a string","url":"hs.hash.html#sha256","kind":"method"},{"fullName":"hs.hash.sha512(data)","description":"Generate SHA512 hash of a string","url":"hs.hash.html#sha512","kind":"method"},{"fullName":"hs.hash.hmacMD5(key, data)","description":"Generate HMAC-MD5 of a string with a key","url":"hs.hash.html#hmacMD5","kind":"method"},{"fullName":"hs.hash.hmacSHA1(key, data)","description":"Generate HMAC-SHA1 of a string with a key","url":"hs.hash.html#hmacSHA1","kind":"method"},{"fullName":"hs.hash.hmacSHA256(key, data)","description":"Generate HMAC-SHA256 of a string with a key","url":"hs.hash.html#hmacSHA256","kind":"method"},{"fullName":"hs.hash.hmacSHA512(key, data)","description":"Generate HMAC-SHA512 of a string with a key","url":"hs.hash.html#hmacSHA512","kind":"method"},{"fullName":"hs.hotkey","description":"Module for creating and managing system-wide hotkeys","url":"hs.hotkey.html","kind":"module"},{"fullName":"hs.hotkey.bind(mods, key, callbackPressed, callbackReleased)","description":"Bind a hotkey cmd / command / ⌘, shift / ⇧, alt / option / ⌥, ctrl / control / ⌃.","url":"hs.hotkey.html#bind","kind":"method"},{"fullName":"hs.hotkey.bindSpec(mods, key, message, callbackPressed, callbackReleased)","description":"Bind a hotkey with a message description","url":"hs.hotkey.html#bindSpec","kind":"method"},{"fullName":"hs.hotkey.getKeyCodeMap()","description":"Get the system-wide mapping of key names to key codes","url":"hs.hotkey.html#getKeyCodeMap","kind":"method"},{"fullName":"hs.hotkey.getModifierMap()","description":"Get the mapping of modifier names to modifier flags","url":"hs.hotkey.html#getModifierMap","kind":"method"},{"fullName":"hs.hotkey.create(mods, key, callbackPressed, callbackReleased)","description":"Create a hotkey without enabling it cmd / command / ⌘, shift / ⇧, alt / option / ⌥, ctrl / control / ⌃.","url":"hs.hotkey.html#create","kind":"method"},{"fullName":"hs.hotkey.createModal(mods, key)","description":"Create a new modal hotkey group, optionally entered via a trigger key combination","url":"hs.hotkey.html#createModal","kind":"method"},{"fullName":"hs.http","description":"HTTP client module for making network requests from JavaScript.","url":"hs.http.html","kind":"module"},{"fullName":"hs.http.get(url, headers)","description":"Perform an HTTP GET request.","url":"hs.http.html#get","kind":"method"},{"fullName":"hs.http.post(url, body, headers)","description":"Perform an HTTP POST request.","url":"hs.http.html#post","kind":"method"},{"fullName":"hs.http.put(url, body, headers)","description":"Perform an HTTP PUT request.","url":"hs.http.html#put","kind":"method"},{"fullName":"hs.http.doRequest(url, method, body, headers)","description":"Perform an HTTP request with any method (GET, POST, PUT, DELETE, PATCH, etc.). Use this for methods not covered by the convenience helpers, such as DELETE or PATCH.","url":"hs.http.html#doRequest","kind":"method"},{"fullName":"hs.http.encodeForQuery(string)","description":"URL-encode a string for use as a query parameter value. Encodes characters that are illegal in a URL query string (including ?, =, +, &, #) using percent-encoding.","url":"hs.http.html#encodeForQuery","kind":"method"},{"fullName":"hs.http.urlParts(url)","description":"Parse a URL into its component parts. Returns an object containing only the fields present in the URL. The queryItems field is an array of {name, value} objects from the query string.","url":"hs.http.html#urlParts","kind":"method"},{"fullName":"hs.http.convertHtmlEntities(string)","description":"Convert HTML entities in a string to their UTF-8 character equivalents. Handles named entities (e.g. &, <, ©), decimal numeric references (&), and hexadecimal numeric references (&).","url":"hs.http.html#convertHtmlEntities","kind":"method"},{"fullName":"hs.http.openWebSocket(url)","description":"Open a WebSocket connection to the given URL. The connection begins immediately. Use the returned object's chainable setter methods to register event callbacks. The connection is automatically closed when hs.reload() is called or the engine shuts down.","url":"hs.http.html#openWebSocket","kind":"method"},{"fullName":"hs.httpserver","description":"Module for creating and managing HTTP servers.","url":"hs.httpserver.html","kind":"module"},{"fullName":"hs.httpserver.create()","description":"Create a new HTTP server instance. The server is not running until you call start() on the returned object.","url":"hs.httpserver.html#create","kind":"method"},{"fullName":"hs.ipc","description":"Module for enabling CLI access to Hammerspoon 2 via the hs command-line tool.","url":"hs.ipc.html","kind":"module"},{"fullName":"hs.ipc.isListening","description":"Whether the IPC server is currently accepting connections.","url":"hs.ipc.html#isListening","kind":"property"},{"fullName":"hs.ipc.start()","description":"Start the IPC server. The server listens on a named XPC Mach service (net.tenshu.Hammerspoon-2.ipc). In release builds, only processes signed with the same Team ID can connect. Calling start() when already running logs a warning and does nothing.","url":"hs.ipc.html#start","kind":"method"},{"fullName":"hs.ipc.stop()","description":"Stop the IPC server and disconnect all connected clients.","url":"hs.ipc.html#stop","kind":"method"},{"fullName":"hs.ipc.installBinary(directory)","description":"Install the hs command-line tool to the given directory as a symlink. Creates a symlink in the target directory that points to the hs binary inside the Hammerspoon 2 app bundle. Using a symlink means the CLI automatically reflects any app update without reinstalling. Any existing hs file at that path is replaced. The directory must be on your $PATH for hs to work without a full path. Permissions: /usr/local/bin is typically user-writable on Intel Macs with Homebrew. On Apple Silicon, prefer /opt/homebrew/bin. On a stock Mac (no Homebrew), both directories require root — if this method returns false, run the logged command in a terminal with sudo.","url":"hs.ipc.html#installBinary","kind":"method"},{"fullName":"hs.ipc.uninstallBinary(directory)","description":"Remove the hs command-line tool from the given directory.","url":"hs.ipc.html#uninstallBinary","kind":"method"},{"fullName":"hs.ipc.isBinaryInstalled(directory)","description":"Check whether the hs command-line tool exists at the given directory.","url":"hs.ipc.html#isBinaryInstalled","kind":"method"},{"fullName":"hs.keycodes","description":"Access information about the current keyboard layout and input sources, and respond to changes.","url":"hs.keycodes.html","kind":"module"},{"fullName":"hs.keycodes.map","description":"A bidirectional mapping between key names and their macOS virtual key codes. Entries exist for both directions: look up a name to get its integer keycode, or look up a keycode (as a string) to get the key name. The map is rebuilt automatically whenever the keyboard input source changes.","url":"hs.keycodes.html#map","kind":"property"},{"fullName":"hs.keycodes.currentLayout()","description":"Returns the localized name of the current keyboard layout. Uses the base keyboard layout, which is the underlying layout even when an input method (such as a CJK input method) is also active.","url":"hs.keycodes.html#currentLayout","kind":"method"},{"fullName":"hs.keycodes.currentMethod()","description":"Returns the localized name of the active input method, or null if none is active. Input methods are distinct from keyboard layouts. They provide complex character composition such as CJK input. Returns null when using a plain keyboard layout with no input method overlay.","url":"hs.keycodes.html#currentMethod","kind":"method"},{"fullName":"hs.keycodes.currentSourceID()","description":"Returns the reverse-DNS identifier of the currently selected keyboard input source.","url":"hs.keycodes.html#currentSourceID","kind":"method"},{"fullName":"hs.keycodes.layouts()","description":"Returns the localized names of all currently enabled keyboard layouts.","url":"hs.keycodes.html#layouts","kind":"method"},{"fullName":"hs.keycodes.methods()","description":"Returns the localized names of all currently enabled input methods.","url":"hs.keycodes.html#methods","kind":"method"},{"fullName":"hs.keycodes.setLayout(layoutName)","description":"Switches the active keyboard layout to the one with the given localized name. Use layouts() to enumerate valid names.","url":"hs.keycodes.html#setLayout","kind":"method"},{"fullName":"hs.keycodes.setMethod(methodName)","description":"Switches the active input method to the one with the given localized name. Use methods() to enumerate valid names.","url":"hs.keycodes.html#setMethod","kind":"method"},{"fullName":"hs.keycodes.setSourceID(sourceID)","description":"Switches the active input source to the one with the given reverse-DNS identifier. Use currentSourceID() to see the current value.","url":"hs.keycodes.html#setSourceID","kind":"method"},{"fullName":"hs.keycodes.addWatcher(listener)","description":"Registers a listener that fires whenever the keyboard input source changes. The listener is called with no arguments. Read currentLayout(), currentSourceID(), or map inside the callback to inspect the new state. The OS subscription starts lazily on the first listener and is released automatically when the last listener is removed via removeWatcher.","url":"hs.keycodes.html#addWatcher","kind":"method"},{"fullName":"hs.keycodes.removeWatcher(listener)","description":"Removes a previously registered input source change listener.","url":"hs.keycodes.html#removeWatcher","kind":"method"},{"fullName":"hs.location","description":"Determine the Mac's location via macOS Location Services.","url":"hs.location.html","kind":"module"},{"fullName":"hs.location.lookupAddress(address)","description":"Geocodes an address string into an array of placemarkTables. Returns a Promise that resolves with an array of placemarkTable objects (sorted by relevance) or rejects with an error message.","url":"hs.location.html#lookupAddress","kind":"method"},{"fullName":"hs.location.lookupLocation(locationTable)","description":"Reverse-geocodes a locationTable into an array of placemarkTables. Returns a Promise that resolves with matching placemarks or rejects with an error.","url":"hs.location.html#lookupLocation","kind":"method"},{"fullName":"hs.location.servicesEnabled()","description":"Returns true if Location Services are enabled system-wide.","url":"hs.location.html#servicesEnabled","kind":"method"},{"fullName":"hs.location.authorizationStatus()","description":"Returns the app's current Location Services authorization status as a string.","url":"hs.location.html#authorizationStatus","kind":"method"},{"fullName":"hs.location.get()","description":"Returns the most recently cached location as a locationTable, or null. Activates Location Services if not already running. The cache is updated periodically while any watcher is running.","url":"hs.location.html#get","kind":"method"},{"fullName":"hs.location.distance(from, to)","description":"Calculates the straight-line distance in metres between two locationTables. Does not require Location Services.","url":"hs.location.html#distance","kind":"method"},{"fullName":"hs.location.sunrise(latitude, longitude, date)","description":"Returns the time of sunrise for the given coordinates and date, or null if the sun does not rise on that date (polar night).","url":"hs.location.html#sunrise","kind":"method"},{"fullName":"hs.location.sunset(latitude, longitude, date)","description":"Returns the time of sunset for the given coordinates and date, or null if the sun does not set on that date (midnight sun).","url":"hs.location.html#sunset","kind":"method"},{"fullName":"hs.location.addWatcher()","description":"Creates a new location watcher object. Call .start() on it to begin receiving updates. The watcher is automatically stopped when the module shuts down.","url":"hs.location.html#addWatcher","kind":"method"},{"fullName":"hs.location.removeWatcher(watcher)","description":"Removes a previously created watcher and stops it if running.","url":"hs.location.html#removeWatcher","kind":"method"},{"fullName":"hs.menubar","description":"Module for creating and managing macOS system menu bar items.","url":"hs.menubar.html","kind":"module"},{"fullName":"hs.menubar.create(hidden)","description":"Create a new menu bar item","url":"hs.menubar.html#create","kind":"method"},{"fullName":"hs.network","description":"Module for inspecting network interfaces, resolving hostnames, and reading system configuration","url":"hs.network.html","kind":"module"},{"fullName":"hs.network.reachabilityFlags","description":"A dictionary of named flag constants for use with HSNetworkReachability.status(). Compare individual bits against these constants to determine which network conditions apply. The numeric values match the deprecated SCNetworkReachabilityFlags for backward compatibility. Keys: transientConnection, reachable, connectionRequired, connectionOnTraffic, interventionRequired, connectionOnDemand, isLocalAddress, isDirect.","url":"hs.network.html#reachabilityFlags","kind":"property"},{"fullName":"hs.network.interfaces()","description":"Returns all network interfaces present on this system. Each object contains name (string), isLoopback (boolean), isUp (boolean), and isRunning (boolean). A displayName string is included when the system provides a human-readable label for the interface (e.g. \"Wi-Fi\" or \"Ethernet\").","url":"hs.network.html#interfaces","kind":"method"},{"fullName":"hs.network.primaryInterface()","description":"Returns the name of the primary network interface, i.e. the one currently providing the default route.","url":"hs.network.html#primaryInterface","kind":"method"},{"fullName":"hs.network.addresses()","description":"Returns all IP addresses assigned to this host. Each object contains interface (the BSD name of the interface), address (the address string), and family (\"ipv4\" or \"ipv6\").","url":"hs.network.html#addresses","kind":"method"},{"fullName":"hs.network.resolve(hostname, family)","description":"Asynchronously resolves a hostname to its IP addresses using the system DNS resolver. Uses CFHost, which respects the system's network configuration including VPN routes and proxy settings.","url":"hs.network.html#resolve","kind":"method"},{"fullName":"hs.network.reachabilityForAddress(address)","description":"Creates a reachability monitor for a specific IP address. Returns null if address is not a valid IPv4 or IPv6 address literal. Under the hood this monitors general system connectivity (the same as reachabilityInternet()), because NWPathMonitor does not support per-address targeting.","url":"hs.network.html#reachabilityForAddress","kind":"method"},{"fullName":"hs.network.reachabilityForAddressPair(localAddress, remoteAddress)","description":"Creates a reachability monitor for a source/destination IP address pair. Returns null if either address is not a valid IPv4 or IPv6 address literal. Under the hood this monitors general system connectivity (the same as reachabilityInternet()), because NWPathMonitor does not support per-address targeting.","url":"hs.network.html#reachabilityForAddressPair","kind":"method"},{"fullName":"hs.network.reachabilityForHostName(hostName)","description":"Creates a reachability monitor for a given hostname. Returns null if hostName is empty. Under the hood this monitors general system connectivity (the same as reachabilityInternet()), because NWPathMonitor does not support per-hostname targeting.","url":"hs.network.html#reachabilityForHostName","kind":"method"},{"fullName":"hs.network.reachabilityInternet()","description":"Creates a reachability monitor for general internet connectivity. This is the most common factory method. Use it when you want to know whether the device currently has a working internet connection.","url":"hs.network.html#reachabilityInternet","kind":"method"},{"fullName":"hs.network.reachabilityLinkLocal()","description":"Creates a reachability monitor for link-local connectivity. Link-local addresses cover the 169.254.x.x (IPv4) and fe80::/10 (IPv6) ranges used for direct device-to-device communication without a router. Under the hood this monitors general system connectivity (the same as reachabilityInternet()), because NWPathMonitor does not distinguish link-local reachability.","url":"hs.network.html#reachabilityLinkLocal","kind":"method"},{"fullName":"hs.network.configurationStore(pattern)","description":"Returns the contents of the macOS System Configuration dynamic store as a dictionary. The store holds live network configuration for the running system — interface addresses, routing, DNS servers, proxy settings, VPN state, and more. Keys follow a hierarchical path convention (e.g. \"State:/Network/Global/IPv4\"). Omit or pass null to return all keys (equivalent to \".*\").","url":"hs.network.html#configurationStore","kind":"method"},{"fullName":"hs.network.configurationLocations()","description":"Returns a mapping of all configured network location UUIDs to their display names. Use this to discover available locations before calling configurationSetLocation().","url":"hs.network.html#configurationLocations","kind":"method"},{"fullName":"hs.network.configurationSetLocation(location)","description":"Switches the active network location to the one with the given name or UUID. Pass the location's display name (e.g. \"Home\") or its UUID from configurationLocations(). The change is applied immediately. Returns false if the location was not found or the preferences could not be committed (e.g. insufficient privileges).","url":"hs.network.html#configurationSetLocation","kind":"method"},{"fullName":"hs.network.configurationWatcher()","description":"Creates a watcher that fires a callback when System Configuration dynamic store keys change. Call setKeys() to specify which keys (or patterns) to watch, setCallback() to register the handler, then start() to begin monitoring. The module automatically stops and destroys all watchers on hs.reload().","url":"hs.network.html#configurationWatcher","kind":"method"},{"fullName":"hs.network.ping(server, options)","description":"Sends ICMP Echo Requests to server and reports results via a callback. DNS resolution and the first ping begin immediately. The returned object can be used to pause, resume, or cancel the ping, and to read statistics. timeout (seconds per packet, default 2.0), family (\"any\" | \"ipv4\" | \"ipv6\", default \"any\"), and callback (function).","url":"hs.network.html#ping","kind":"method"},{"fullName":"hs.notify","description":"Module for creating and displaying macOS system notifications.","url":"hs.notify.html","kind":"module"},{"fullName":"hs.notify.show(title, body, callback)","description":"Display a notification immediately.","url":"hs.notify.html#show","kind":"method"},{"fullName":"hs.notify.create(options)","description":"Create a richly configured notification without sending it yet.","url":"hs.notify.html#create","kind":"method"},{"fullName":"hs.notify.removeAllDelivered()","description":"Remove all delivered Hammerspoon notifications from Notification Center.","url":"hs.notify.html#removeAllDelivered","kind":"method"},{"fullName":"hs.notify.removeAllPending()","description":"Cancel all pending (not yet delivered) Hammerspoon notifications.","url":"hs.notify.html#removeAllPending","kind":"method"},{"fullName":"hs.ocr","description":"Recognize text in images using Apple's Vision framework.","url":"hs.ocr.html","kind":"module"},{"fullName":"hs.ocr.recognizeText(path, options)","description":"Recognize text in the image at the given file path. Returns a Promise that resolves with an HSOCRResult containing all recognized text and per-region observations. The image must exist on disk; URLs and data buffers are not supported. Recognition is performed on a background thread; the main thread is not blocked during the operation. \"accurate\" uses a larger neural network for better results; \"fast\" trades accuracy for speed. Observations whose confidence is below this threshold are excluded from result.observations (and therefore from result.text). Hints Vision toward specific languages. Use supportedLanguages() to enumerate the available codes for the current device. When true, Vision selects recognition languages automatically. Overrides languages when set.","url":"hs.ocr.html#recognizeText","kind":"method"},{"fullName":"hs.ocr.supportedLanguages()","description":"Returns the BCP-47 language codes supported by the Vision text recognizer on this device. The set of languages varies between macOS versions and hardware. Call this at runtime to discover which codes are valid for the languages option passed to recognizeText().","url":"hs.ocr.html#supportedLanguages","kind":"method"},{"fullName":"hs.osascript","description":"Run AppleScript and OSA JavaScript from Hammerspoon scripts.","url":"hs.osascript.html","kind":"module"},{"fullName":"hs.osascript.applescript(source)","description":"Run an AppleScript source string.","url":"hs.osascript.html#applescript","kind":"method"},{"fullName":"hs.osascript.javascript(source)","description":"Run an OSA JavaScript source string. OSA JavaScript is Apple's Open Scripting Architecture dialect of JavaScript, distinct from the JavaScriptCore engine that runs Hammerspoon scripts themselves.","url":"hs.osascript.html#javascript","kind":"method"},{"fullName":"hs.osascript.applescriptFromFile(path)","description":"Read a file from disk and execute its contents as AppleScript. The file is read in the main process before being sent to the XPC helper. If the file cannot be read the promise resolves immediately with { success: false, result: null, raw: \"Failed to read file: \" }.","url":"hs.osascript.html#applescriptFromFile","kind":"method"},{"fullName":"hs.osascript.javascriptFromFile(path)","description":"Read a file from disk and execute its contents as OSA JavaScript. The file is read in the main process before being sent to the XPC helper. If the file cannot be read the promise resolves immediately with { success: false, result: null, raw: \"Failed to read file: \" }.","url":"hs.osascript.html#javascriptFromFile","kind":"method"},{"fullName":"hs.osascript._execute(source, language)","description":"Low-level execution entry point used by the higher-level helpers. Prefer applescript() or javascript() over calling this directly.","url":"hs.osascript.html#_execute","kind":"method"},{"fullName":"hs.osascript.applescriptSync(source)","description":"Run an AppleScript source string synchronously. Blocks the JS thread until the script completes.","url":"hs.osascript.html#applescriptSync","kind":"method"},{"fullName":"hs.osascript.javascriptSync(source)","description":"Run an OSA JavaScript source string synchronously. Blocks the JS thread until the script completes.","url":"hs.osascript.html#javascriptSync","kind":"method"},{"fullName":"hs.osascript.applescriptSyncFromFile(path)","description":"Read a file from disk and execute its contents as AppleScript synchronously.","url":"hs.osascript.html#applescriptSyncFromFile","kind":"method"},{"fullName":"hs.osascript.javascriptSyncFromFile(path)","description":"Read a file from disk and execute its contents as OSA JavaScript synchronously.","url":"hs.osascript.html#javascriptSyncFromFile","kind":"method"},{"fullName":"hs.osascript._executeSync(source, language)","description":"Low-level synchronous execution entry point. Prefer applescriptSync() or javascriptSync() over calling this directly.","url":"hs.osascript.html#_executeSync","kind":"method"},{"fullName":"hs.pasteboard","description":"Module for interacting with the macOS pasteboard (clipboard)","url":"hs.pasteboard.html","kind":"module"},{"fullName":"hs.pasteboard.changeCount","description":"The pasteboard change count. Increments each time any application writes to the pasteboard. Comparing a saved value to the current value is the standard way to detect external changes.","url":"hs.pasteboard.html#changeCount","kind":"property"},{"fullName":"hs.pasteboard.watcherInterval","description":"The polling interval for the pasteboard watcher, in seconds. Defaults to 0.5. Changes take effect the next time a watcher is started (i.e. after removing and re-adding).","url":"hs.pasteboard.html#watcherInterval","kind":"property"},{"fullName":"hs.pasteboard.readString()","description":"Read plain text from the pasteboard","url":"hs.pasteboard.html#readString","kind":"method"},{"fullName":"hs.pasteboard.readHTML()","description":"Read HTML from the pasteboard","url":"hs.pasteboard.html#readHTML","kind":"method"},{"fullName":"hs.pasteboard.readRTF()","description":"Read RTF from the pasteboard","url":"hs.pasteboard.html#readRTF","kind":"method"},{"fullName":"hs.pasteboard.readURL()","description":"Read a URL from the pasteboard","url":"hs.pasteboard.html#readURL","kind":"method"},{"fullName":"hs.pasteboard.readImage()","description":"Read an image from the pasteboard","url":"hs.pasteboard.html#readImage","kind":"method"},{"fullName":"hs.pasteboard.readData(uti)","description":"Read raw data for a specific UTI type, returned as a base64-encoded string. Use this for types not covered by the convenience read methods.","url":"hs.pasteboard.html#readData","kind":"method"},{"fullName":"hs.pasteboard.writeString(str)","description":"Write plain text to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeString","kind":"method"},{"fullName":"hs.pasteboard.writeHTML(html)","description":"Write HTML to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeHTML","kind":"method"},{"fullName":"hs.pasteboard.writeRTF(rtf)","description":"Write RTF to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeRTF","kind":"method"},{"fullName":"hs.pasteboard.writeURL(url)","description":"Write a URL to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeURL","kind":"method"},{"fullName":"hs.pasteboard.writeImage(image)","description":"Write an image to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeImage","kind":"method"},{"fullName":"hs.pasteboard.writeData(base64, uti)","description":"Write raw base64-encoded data for a specific UTI type, replacing all current contents. Use this for types not covered by the convenience write methods.","url":"hs.pasteboard.html#writeData","kind":"method"},{"fullName":"hs.pasteboard.writeObjects(representations)","description":"Write multiple type representations to the pasteboard atomically, replacing all current contents. Keys must be UTI type strings; values must be strings. This is how you provide both a plain-text fallback and a richer representation (such as HTML) in a single clipboard operation.","url":"hs.pasteboard.html#writeObjects","kind":"method"},{"fullName":"hs.pasteboard.types()","description":"Get all UTI type strings currently on the pasteboard, across all items","url":"hs.pasteboard.html#types","kind":"method"},{"fullName":"hs.pasteboard.hasType(uti)","description":"Check whether a specific UTI type is currently available on the pasteboard","url":"hs.pasteboard.html#hasType","kind":"method"},{"fullName":"hs.pasteboard.clear()","description":"Clear all contents from the pasteboard","url":"hs.pasteboard.html#clear","kind":"method"},{"fullName":"hs.pasteboard.addWatcher(listener)","description":"Add a watcher that is called whenever the pasteboard contents change. Multiple watchers may be registered; they are each called independently. Because macOS provides no pasteboard change notification API, this is implemented by polling changeCount at the interval specified by watcherInterval.","url":"hs.pasteboard.html#addWatcher","kind":"method"},{"fullName":"hs.pasteboard.removeWatcher(listener)","description":"Remove a previously registered pasteboard watcher","url":"hs.pasteboard.html#removeWatcher","kind":"method"},{"fullName":"hs.permissions","description":"Module for checking and requesting system permissions","url":"hs.permissions.html","kind":"module"},{"fullName":"hs.permissions.checkAccessibility()","description":"Check if the app has Accessibility permission","url":"hs.permissions.html#checkAccessibility","kind":"method"},{"fullName":"hs.permissions.requestAccessibility()","description":"Request Accessibility permission (shows system dialog if not granted)","url":"hs.permissions.html#requestAccessibility","kind":"method"},{"fullName":"hs.permissions.checkScreenRecording()","description":"Check if the app has Screen Recording permission","url":"hs.permissions.html#checkScreenRecording","kind":"method"},{"fullName":"hs.permissions.requestScreenRecording()","description":"Request Screen Recording permission","url":"hs.permissions.html#requestScreenRecording","kind":"method"},{"fullName":"hs.permissions.checkCamera()","description":"Check if the app has Camera permission","url":"hs.permissions.html#checkCamera","kind":"method"},{"fullName":"hs.permissions.requestCamera()","description":"Request Camera permission (shows system dialog if not granted)","url":"hs.permissions.html#requestCamera","kind":"method"},{"fullName":"hs.permissions.checkMicrophone()","description":"Check if the app has Microphone permission","url":"hs.permissions.html#checkMicrophone","kind":"method"},{"fullName":"hs.permissions.requestMicrophone()","description":"Request Microphone permission (shows system dialog if not granted)","url":"hs.permissions.html#requestMicrophone","kind":"method"},{"fullName":"hs.permissions.checkNotifications()","description":"Check if the app has permission to display notifications. The result is cached from the last request or check; the cache is refreshed asynchronously, so the very first call in a session may return false before the cached value is populated. Use requestNotifications() on first launch to ensure the result is accurate.","url":"hs.permissions.html#checkNotifications","kind":"method"},{"fullName":"hs.permissions.requestNotifications()","description":"Request notification permission (shows the system dialog if the user has not yet decided). It is safe to call this on every launch — the dialog only appears once; subsequent calls resolve immediately with the previously granted or denied state.","url":"hs.permissions.html#requestNotifications","kind":"method"},{"fullName":"hs.permissions.checkLocation()","description":"Check if the app has Location permission.","url":"hs.permissions.html#checkLocation","kind":"method"},{"fullName":"hs.permissions.requestLocation()","description":"Request Location permission (shows the system dialog if the user has not yet decided).","url":"hs.permissions.html#requestLocation","kind":"method"},{"fullName":"hs.power","description":"Monitor and control system power: prevent sleep, read battery state, respond to power events, and lock or sleep the machine.","url":"hs.power.html","kind":"module"},{"fullName":"hs.power.percentage","description":"The current battery charge percentage (0–100), or -1 if no battery is present.","url":"hs.power.html#percentage","kind":"property"},{"fullName":"hs.power.isCharging","description":"Whether the battery is currently charging. Returns false when no battery is present.","url":"hs.power.html#isCharging","kind":"property"},{"fullName":"hs.power.powerSource","description":"The current power source. Returns \"ac\" when plugged in, \"battery\" when on battery power, \"ups\" when powered by a UPS, or \"unknown\" if the source cannot be determined.","url":"hs.power.html#powerSource","kind":"property"},{"fullName":"hs.power.isLowPowerMode","description":"Whether Low Power Mode is currently active.","url":"hs.power.html#isLowPowerMode","kind":"property"},{"fullName":"hs.power.thermalState","description":"The current thermal state of the system. Returns one of: \"nominal\", \"fair\", \"serious\", \"critical\".","url":"hs.power.html#thermalState","kind":"property"},{"fullName":"hs.power.preventSleep(type)","description":"Prevents the specified type of system sleep. Creates an IOKit power assertion that stops macOS from allowing the specified type of sleep. Call allowSleep with the same type to release the assertion. idle sleep), \"systemIdle\" (prevent system idle sleep), \"system\" (prevent all system sleep, including from power button or lid close).","url":"hs.power.html#preventSleep","kind":"method"},{"fullName":"hs.power.allowSleep(type)","description":"Releases a previously created sleep prevention assertion.","url":"hs.power.html#allowSleep","kind":"method"},{"fullName":"hs.power.isSleepPrevented(type)","description":"Returns whether Hammerspoon is currently preventing the specified type of sleep.","url":"hs.power.html#isSleepPrevented","kind":"method"},{"fullName":"hs.power.declareActivity()","description":"Simulates user activity, briefly resetting the display idle timer. Equivalent to moving the mouse — does not create a persistent assertion.","url":"hs.power.html#declareActivity","kind":"method"},{"fullName":"hs.power.currentAssertions()","description":"Returns the active power management assertions from all processes on the system.","url":"hs.power.html#currentAssertions","kind":"method"},{"fullName":"hs.power.systemSleep()","description":"Puts the system to sleep immediately. Requires the Automation permission for System Events.","url":"hs.power.html#systemSleep","kind":"method"},{"fullName":"hs.power.lockScreen()","description":"Locks the screen immediately.","url":"hs.power.html#lockScreen","kind":"method"},{"fullName":"hs.power.startScreensaver()","description":"Starts the screensaver immediately.","url":"hs.power.html#startScreensaver","kind":"method"},{"fullName":"hs.power.batteryInfo()","description":"Returns a snapshot of all available battery information, or null if no battery is present.","url":"hs.power.html#batteryInfo","kind":"method"},{"fullName":"hs.power.addEventWatcher(listener)","description":"Registers a listener that fires when system power events occur. \"screensDidSleep\", \"screensDidWake\", \"screensDidLock\", \"screensDidUnlock\", \"screensaverDidStart\", \"screensaverDidStop\", \"screensaverWillStop\", \"systemWillSleep\", \"systemDidWake\", \"systemWillPowerOff\", \"sessionDidBecomeActive\", \"sessionDidResignActive\". The OS notification subscription starts lazily on the first listener and is released automatically when the last listener is removed.","url":"hs.power.html#addEventWatcher","kind":"method"},{"fullName":"hs.power.removeEventWatcher(listener)","description":"Removes a previously registered power event listener.","url":"hs.power.html#removeEventWatcher","kind":"method"},{"fullName":"hs.power.addBatteryWatcher(listener)","description":"Registers a listener that fires whenever battery state changes. The listener receives no arguments; call batteryInfo() or read individual properties inside the callback to determine what changed. The OS notification subscription starts lazily on the first listener and is released automatically when the last listener is removed.","url":"hs.power.html#addBatteryWatcher","kind":"method"},{"fullName":"hs.power.removeBatteryWatcher(listener)","description":"Removes a previously registered battery change listener.","url":"hs.power.html#removeBatteryWatcher","kind":"method"},{"fullName":"hs.screen","description":"Inspect and control the displays attached to the system.","url":"hs.screen.html","kind":"module"},{"fullName":"hs.screen.all()","description":"All connected screens.","url":"hs.screen.html#all","kind":"method"},{"fullName":"hs.screen.main()","description":"The screen that currently contains the focused window, or the screen with the keyboard focus if no window is focused.","url":"hs.screen.html#main","kind":"method"},{"fullName":"hs.screen.primary()","description":"The primary display — the one that contains the global menu bar.","url":"hs.screen.html#primary","kind":"method"},{"fullName":"hs.shortcuts","description":"Run and interact with macOS Shortcuts from JavaScript.","url":"hs.shortcuts.html","kind":"module"},{"fullName":"hs.shortcuts.list()","description":"Returns an array of all available shortcuts. | Key | Type | Description | |-----|------|-------------| | name | string | The display name of the shortcut | | id | string | A UUID uniquely identifying the shortcut | | acceptsInput | boolean | Whether the shortcut expects input when run | | actionCount | number | How many actions the shortcut contains |","url":"hs.shortcuts.html#list","kind":"method"},{"fullName":"hs.shortcuts.run(name)","description":"Runs a Shortcuts shortcut by name and returns any output. Executes the shortcut in the background via the shortcuts CLI tool. If the shortcut produces output (via a \"Stop and Output\" action), the Promise resolves with that string. If the shortcut produces no output, the Promise resolves with null. The Promise rejects if the shortcut cannot be found or exits with a non-zero status.","url":"hs.shortcuts.html#run","kind":"method"},{"fullName":"hs.shortcuts.open(name)","description":"Opens a shortcut in the Shortcuts app for viewing or editing. Uses the shortcuts://open-shortcut URL scheme to bring Shortcuts to the foreground and navigate directly to the named shortcut.","url":"hs.shortcuts.html#open","kind":"method"},{"fullName":"hs.sound","description":"Play audio from files on disk or from the system's built-in sound library.","url":"hs.sound.html","kind":"module"},{"fullName":"hs.sound.fromFile(path)","description":"Loads an audio file from the given path and returns a sound object. Returns null if the file cannot be loaded.","url":"hs.sound.html#fromFile","kind":"method"},{"fullName":"hs.sound.named(name)","description":"Creates a sound object for a built-in system sound by name. Returns null if no sound with that name can be found. Use hs.sound.systemSounds() to discover available names.","url":"hs.sound.html#named","kind":"method"},{"fullName":"hs.sound.systemSounds()","description":"Returns a sorted array of all available system sound names. These names can be passed directly to hs.sound.named(). Scans /System/Library/Sounds, /Library/Sounds, and ~/Library/Sounds.","url":"hs.sound.html#systemSounds","kind":"method"},{"fullName":"hs.spotlight","description":"Query the macOS Spotlight metadata database.","url":"hs.spotlight.html","kind":"module"},{"fullName":"hs.spotlight.scope","description":"Predefined search scope constants for use with HSSpotlightQuery.setScopes(). | Key | Description | |-----|-------------| | home | The current user's home directory | | computer | All locally mounted volumes | | network | Network-mounted volumes | | applications | Common locations for .app bundles | | icloud | iCloud Documents | | icloudData | iCloud Data (non-document ubiquitous files) |","url":"hs.spotlight.html#scope","kind":"property"},{"fullName":"hs.spotlight.attribute","description":"Common Spotlight metadata attribute key shortcuts. These are plain kMDItem* string values — using them is equivalent to typing the raw key name, but they provide autocomplete and avoid typos. | Key | Attribute | Description | |-----|-----------|-------------| | path | kMDItemPath | Absolute filesystem path | | displayName | kMDItemDisplayName | User-visible display name | | fsName | kMDItemFSName | Filename on disk | | contentType | kMDItemContentType | UTI content type | | contentTypeTree | kMDItemContentTypeTree | Full UTI conformance tree | | kind | kMDItemKind | Finder \"Kind\" string | | fileSize | kMDItemFSSize | File size in bytes | | creationDate | kMDItemFSCreationDate | Filesystem creation date | | modifiedDate | kMDItemFSContentChangeDate | Last content modification date | | lastUsedDate | kMDItemLastUsedDate | Last time the item was opened | | useCount | kMDItemUseCount | Number of times opened | | authors | kMDItemAuthors | Document authors | | title | kMDItemTitle | Document title | | comment | kMDItemComment | User comment | | keywords | kMDItemKeywords | Tags/keywords | | durationSeconds | kMDItemDurationSeconds | Media duration in seconds | | pixelWidth | kMDItemPixelWidth | Image/video width in pixels | | pixelHeight | kMDItemPixelHeight | Image/video height in pixels | | whereFroms | kMDItemWhereFroms | Download source URLs | | bundleIdentifier | kMDItemCFBundleIdentifier | App bundle identifier |","url":"hs.spotlight.html#attribute","kind":"property"},{"fullName":"hs.spotlight.create()","description":"Creates and returns a new, unconfigured Spotlight query. Configure it with setQuery(), setScopes(), and setCallback(), then call start(). The query is automatically stopped and released when the module shuts down.","url":"hs.spotlight.html#create","kind":"method"},{"fullName":"hs.spotlight.search(predicate, callback)","description":"Convenience helper that creates, configures, and starts a query in one call. Equivalent to create().setQuery(predicate).setCallback(callback).start(). Call q.stop() from inside callback (when event === 'didFinish') to end the search once you have what you need.","url":"hs.spotlight.html#search","kind":"method"},{"fullName":"hs.task","description":"Module for running external processes","url":"hs.task.html","kind":"module"},{"fullName":"hs.task.sequence","description":"Run multiple tasks in sequence. Swift-retained storage for the JS implementation.","url":"hs.task.html#sequence","kind":"property"},{"fullName":"hs.task.TaskBuilder","description":"TaskBuilder class. Swift-retained storage for the JS implementation.","url":"hs.task.html#TaskBuilder","kind":"property"},{"fullName":"hs.task.create(launchPath, arguments, completionCallback, environment, streamingCallback)","description":"Create a new task","url":"hs.task.html#create","kind":"method"},{"fullName":"hs.task.runAsync(launchPath, args, options, legacyStreamCallback)","description":"Create and run a task asynchronously","url":"hs.task.html#runAsync","kind":"method"},{"fullName":"hs.task.shell(command, options)","description":"Run a shell command asynchronously","url":"hs.task.html#shell","kind":"method"},{"fullName":"hs.task.parallel()","description":"Run multiple tasks in parallel","url":"hs.task.html#parallel","kind":"method"},{"fullName":"hs.task.builder(launchPath)","description":"Create a task builder for fluent API","url":"hs.task.html#builder","kind":"method"},{"fullName":"hs.timer","description":"Module for creating and managing timers","url":"hs.timer.html","kind":"module"},{"fullName":"hs.timer.create(interval, callback, continueOnError)","description":"Create a new timer","url":"hs.timer.html#create","kind":"method"},{"fullName":"hs.timer.doAfter(seconds, callback)","description":"Create and start a one-shot timer","url":"hs.timer.html#doAfter","kind":"method"},{"fullName":"hs.timer.doEvery(interval, callback)","description":"Create and start a repeating timer","url":"hs.timer.html#doEvery","kind":"method"},{"fullName":"hs.timer.doAt(time, repeatInterval, callback, continueOnError)","description":"Create and start a timer that fires at a specific time","url":"hs.timer.html#doAt","kind":"method"},{"fullName":"hs.timer.usleep(microseconds)","description":"Block execution for a specified number of microseconds (strongly discouraged)","url":"hs.timer.html#usleep","kind":"method"},{"fullName":"hs.timer.secondsSinceEpoch()","description":"Get the current time as seconds since the UNIX epoch with sub-second precision","url":"hs.timer.html#secondsSinceEpoch","kind":"method"},{"fullName":"hs.timer.absoluteTime()","description":"Get the number of nanoseconds since the system was booted (excluding sleep time)","url":"hs.timer.html#absoluteTime","kind":"method"},{"fullName":"hs.timer.localTime()","description":"Get the number of seconds since local midnight","url":"hs.timer.html#localTime","kind":"method"},{"fullName":"hs.timer.minutes(n)","description":"Converts minutes to seconds","url":"hs.timer.html#minutes","kind":"method"},{"fullName":"hs.timer.hours(n)","description":"Converts hours to seconds","url":"hs.timer.html#hours","kind":"method"},{"fullName":"hs.timer.days(n)","description":"Converts days to seconds","url":"hs.timer.html#days","kind":"method"},{"fullName":"hs.timer.weeks(n)","description":"Converts weeks to seconds","url":"hs.timer.html#weeks","kind":"method"},{"fullName":"hs.timer.doUntil(predicateFn, actionFn, checkInterval)","description":"Repeat a function/lambda until a given predicate function/lambda returns true","url":"hs.timer.html#doUntil","kind":"method"},{"fullName":"hs.timer.doWhile(predicateFn, actionFn, checkInterval)","description":"Repeat a function/lambda while a given predicate function/lambda returns true","url":"hs.timer.html#doWhile","kind":"method"},{"fullName":"hs.timer.waitUntil(predicateFn, actionFn, checkInterval)","description":"Wait to call a function/lambda until a given predicate function/lambda returns true","url":"hs.timer.html#waitUntil","kind":"method"},{"fullName":"hs.timer.waitWhile(predicateFn, actionFn, checkInterval)","description":"Wait to call a function/lambda until a given predicate function/lambda returns false","url":"hs.timer.html#waitWhile","kind":"method"},{"fullName":"hs.translation","description":"Translate text between languages using the macOS on-device Translation framework.","url":"hs.translation.html","kind":"module"},{"fullName":"hs.translation.supportedLanguages()","description":"All language codes supported by the on-device translation engine. Resolves to an array of BCP-47 identifiers (e.g. [\"ar\", \"de\", \"en\", \"es\", \"fr\"]). This covers every language the framework knows about, regardless of whether the packs are installed locally. Use status() to distinguish installed pairs from merely supported ones.","url":"hs.translation.html#supportedLanguages","kind":"method"},{"fullName":"hs.translation.status(sourceLanguage, targetLanguage)","description":"Check the installation status of a language pair.","url":"hs.translation.html#status","kind":"method"},{"fullName":"hs.translation.session(sourceLanguage, targetLanguage)","description":"Create a translation session for a language pair. Returns an HSTranslationSession, or null if the system is running macOS older than 26.0.","url":"hs.translation.html#session","kind":"method"},{"fullName":"hs.ui","description":"# hs.ui","url":"hs.ui.html","kind":"module"},{"fullName":"hs.ui.window(dict)","description":"Create a custom UI window Creates a borderless window that can contain custom UI elements built using a declarative, SwiftUI-like syntax with shapes, text, and layout containers.","url":"hs.ui.html#window","kind":"method"},{"fullName":"hs.ui.alert(message)","description":"Create a temporary on-screen alert Displays a temporary notification that automatically dismisses after the specified duration. Similar to the old hs.alert module but with more features.","url":"hs.ui.html#alert","kind":"method"},{"fullName":"hs.ui.dialog(message)","description":"Create a modal dialog with buttons Shows a blocking dialog with customizable message, informative text, and buttons. Use the callback to handle button presses.","url":"hs.ui.html#dialog","kind":"method"},{"fullName":"hs.ui.textPrompt(message)","description":"Create a text input prompt Shows a modal dialog with a text input field. The callback receives the button index and the entered text.","url":"hs.ui.html#textPrompt","kind":"method"},{"fullName":"hs.ui.string(initialValue)","description":"Create a reactive string for binding text element content to a dynamic value An HSString is a reactive value container. When passed to .text(), the canvas automatically re-renders whenever .set() is called from JavaScript.","url":"hs.ui.html#string","kind":"method"},{"fullName":"hs.ui.filePicker()","description":"Create a file or directory picker Shows a standard macOS file picker dialog. Can be configured to select files, directories, or both, with support for file type filtering and multiple selection.","url":"hs.ui.html#filePicker","kind":"method"},{"fullName":"hs.ui.webview()","description":"Create a web browser element for embedding in hs.ui.window (macOS 26+) Returns a UIWebView element that you configure and then embed in any hs.ui.window via .webview(element). The element fills the available space inside the window layout. Keep a reference to call navigation methods after the window is shown.","url":"hs.ui.html#webview","kind":"method"},{"fullName":"hs.urlevent","description":"Handle URL events received by Hammerspoon 2.","url":"hs.urlevent.html","kind":"module"},{"fullName":"hs.urlevent.httpCallback","description":"Callback invoked when Hammerspoon 2 receives an http:// or https:// URL. Fires only when Hammerspoon 2 is the system default handler for http/https. Assign null to remove the callback.","url":"hs.urlevent.html#httpCallback","kind":"property"},{"fullName":"hs.urlevent.mailtoCallback","description":"Callback invoked when Hammerspoon 2 receives a mailto: URL. Fires only when Hammerspoon 2 is the system default handler for mailto. Assign null to remove the callback.","url":"hs.urlevent.html#mailtoCallback","kind":"property"},{"fullName":"hs.urlevent.bind(eventName, callback)","description":"Register or remove a callback for a named hammerspoon2:// URL event. The URL format is hammerspoon2://eventName?key=value. The host component (eventName) selects the callback to invoke.","url":"hs.urlevent.html#bind","kind":"method"},{"fullName":"hs.urlevent.openURL(urlString)","description":"Open a URL using the system default application for its scheme.","url":"hs.urlevent.html#openURL","kind":"method"},{"fullName":"hs.urlevent.openURLWithBundle(urlString, bundleID)","description":"Open a URL with a specific application identified by bundle ID.","url":"hs.urlevent.html#openURLWithBundle","kind":"method"},{"fullName":"hs.urlevent.getDefaultHandler(scheme)","description":"Returns the bundle identifier of the default application for a URL scheme.","url":"hs.urlevent.html#getDefaultHandler","kind":"method"},{"fullName":"hs.urlevent.getAllHandlersForScheme(scheme)","description":"Returns all bundle identifiers capable of handling a URL scheme.","url":"hs.urlevent.html#getAllHandlersForScheme","kind":"method"},{"fullName":"hs.urlevent.setDefaultHandler(scheme, bundleID)","description":"Set the default application for a URL scheme. macOS may display a confirmation dialog for sensitive schemes such as http and https. For custom schemes (hammerspoon2) no dialog is shown.","url":"hs.urlevent.html#setDefaultHandler","kind":"method"},{"fullName":"hs.usb","description":"Module for monitoring USB device connections and disconnections","url":"hs.usb.html","kind":"module"},{"fullName":"hs.usb.attachedDevices()","description":"Returns all currently attached USB devices.","url":"hs.usb.html#attachedDevices","kind":"method"},{"fullName":"hs.usb.addWatcher(listener)","description":"Register a listener for USB device connection and disconnection events. The listener is called with two arguments: the event type string (\"added\" or \"removed\") and a device-info object with the same fields as attachedDevices().","url":"hs.usb.html#addWatcher","kind":"method"},{"fullName":"hs.usb.removeWatcher(listener)","description":"Remove a previously registered USB event listener.","url":"hs.usb.html#removeWatcher","kind":"method"},{"fullName":"hs.window","description":"Module for interacting with windows","url":"hs.window.html","kind":"module"},{"fullName":"hs.window.focusedWindow()","description":"Get the currently focused window","url":"hs.window.html#focusedWindow","kind":"method"},{"fullName":"hs.window.allWindows()","description":"Get all windows from all applications","url":"hs.window.html#allWindows","kind":"method"},{"fullName":"hs.window.visibleWindows()","description":"Get all visible (not minimized) windows","url":"hs.window.html#visibleWindows","kind":"method"},{"fullName":"hs.window.windowsForApp(app)","description":"Get windows for a specific application","url":"hs.window.html#windowsForApp","kind":"method"},{"fullName":"hs.window.windowsOnScreen(screenIndex)","description":"Get all windows on a specific screen","url":"hs.window.html#windowsOnScreen","kind":"method"},{"fullName":"hs.window.windowAtPoint(point)","description":"Get the window at a specific screen position","url":"hs.window.html#windowAtPoint","kind":"method"},{"fullName":"hs.window.orderedWindows()","description":"Get ordered windows (front to back)","url":"hs.window.html#orderedWindows","kind":"method"},{"fullName":"hs.window.findByTitle(title)","description":"Find windows by title Parameter title: The window title to search for. All windows with titles that include this string, will be matched","url":"hs.window.html#findByTitle","kind":"method"},{"fullName":"hs.window.currentWindows()","description":"Get all windows for the current application","url":"hs.window.html#currentWindows","kind":"method"},{"fullName":"hs.window.moveToLeftHalf(win)","description":"Move a window to left half of screen Parameter win: An HSWindow object","url":"hs.window.html#moveToLeftHalf","kind":"method"},{"fullName":"hs.window.moveToRightHalf(win)","description":"Move a window to right half of screen Parameter win: An HSWindow object","url":"hs.window.html#moveToRightHalf","kind":"method"},{"fullName":"hs.window.maximize(win)","description":"Maximize a window Parameter win: An HSWindow object","url":"hs.window.html#maximize","kind":"method"},{"fullName":"hs.window.cycleWindows()","description":"SKIP_DOCS","url":"hs.window.html#cycleWindows","kind":"method"},{"fullName":"HSApplication","description":"Object representing an application. You should not instantiate this directly in JavaScript, but rather, use the methods from hs.application which will return appropriate HSApplication objects.","url":"HSApplication.html","kind":"type"},{"fullName":"HSApplication.pid","description":"POSIX Process Identifier","url":"HSApplication.html#pid","kind":"property"},{"fullName":"HSApplication.bundleID","description":"Bundle Identifier (e.g. com.apple.Safari)","url":"HSApplication.html#bundleID","kind":"property"},{"fullName":"HSApplication.title","description":"The application's title","url":"HSApplication.html#title","kind":"property"},{"fullName":"HSApplication.bundlePath","description":"Location of the application on disk","url":"HSApplication.html#bundlePath","kind":"property"},{"fullName":"HSApplication.isHidden","description":"Is the application hidden","url":"HSApplication.html#isHidden","kind":"property"},{"fullName":"HSApplication.isActive","description":"Is the application focused","url":"HSApplication.html#isActive","kind":"property"},{"fullName":"HSApplication.mainWindow","description":"The main window of this application, or nil if there is no main window","url":"HSApplication.html#mainWindow","kind":"property"},{"fullName":"HSApplication.focusedWindow","description":"The focused window of this application, or nil if there is no focused window","url":"HSApplication.html#focusedWindow","kind":"property"},{"fullName":"HSApplication.allWindows","description":"All windows of this application","url":"HSApplication.html#allWindows","kind":"property"},{"fullName":"HSApplication.visibleWindows","description":"All visible (ie non-hidden) windows of this application","url":"HSApplication.html#visibleWindows","kind":"property"},{"fullName":"HSApplication.isRunning","description":"Whether the application process is still running","url":"HSApplication.html#isRunning","kind":"property"},{"fullName":"HSApplication.kind","description":"The kind of application: \"standard\" (regular dock app), \"accessory\" (no dock), or \"background\" (agent)","url":"HSApplication.html#kind","kind":"property"},{"fullName":"HSApplication.kill()","description":"Terminate the application","url":"HSApplication.html#kill","kind":"method"},{"fullName":"HSApplication.kill9()","description":"Force-terminate the application","url":"HSApplication.html#kill9","kind":"method"},{"fullName":"HSApplication.axElement()","description":"The application's HSAXElement object, for use with the hs.ax APIs","url":"HSApplication.html#axElement","kind":"method"},{"fullName":"HSApplication.activate(allWindows)","description":"Bring this application to the foreground","url":"HSApplication.html#activate","kind":"method"},{"fullName":"HSApplication.hide()","description":"Hide this application and all its windows","url":"HSApplication.html#hide","kind":"method"},{"fullName":"HSApplication.unhide()","description":"Unhide this application","url":"HSApplication.html#unhide","kind":"method"},{"fullName":"HSApplication.getMenuItems()","description":"Get the full menu structure of this application","url":"HSApplication.html#getMenuItems","kind":"method"},{"fullName":"HSApplication.findMenuItemByName(name)","description":"Find a menu item by searching all menus for a matching title (case-insensitive)","url":"HSApplication.html#findMenuItemByName","kind":"method"},{"fullName":"HSApplication.findMenuItemByPath(path)","description":"Find a menu item by following a hierarchical path of titles","url":"HSApplication.html#findMenuItemByPath","kind":"method"},{"fullName":"HSApplication.selectMenuItemByName(name)","description":"Click a menu item found by searching all menus for a matching title (case-insensitive)","url":"HSApplication.html#selectMenuItemByName","kind":"method"},{"fullName":"HSApplication.selectMenuItemByPath(path)","description":"Click a menu item found by following a hierarchical path of titles","url":"HSApplication.html#selectMenuItemByPath","kind":"method"},{"fullName":"HSApplication.findWindow(pattern)","description":"Find windows whose title contains the given string (case-insensitive)","url":"HSApplication.html#findWindow","kind":"method"},{"fullName":"HSApplication.getWindow(title)","description":"Get the first window with exactly the given title","url":"HSApplication.html#getWindow","kind":"method"},{"fullName":"HSAudioDevice","description":"An audio device attached to the system. Obtain instances via `hs.audiodevice module methods — do not instantiate directly. ## Getting and setting volume `javascript const dev = hs.audiodevice.defaultOutputDevice(); if (dev) { console.log(dev.volume); // 0.0 – 1.0, or null dev.volume = 0.5; } ` ## Watching for changes `javascript const dev = hs.audiodevice.defaultOutputDevice(); if (dev) { var fn = function(event) { console.log(\"Device event:\", event); }; dev.addWatcher(fn); // later… dev.removeWatcher(fn); } ``","url":"HSAudioDevice.html","kind":"type"},{"fullName":"HSAudioDevice.id","description":"The CoreAudio object ID of this device.","url":"HSAudioDevice.html#id","kind":"property"},{"fullName":"HSAudioDevice.name","description":"The human-readable name of this device (e.g. \"Built-in Output\").","url":"HSAudioDevice.html#name","kind":"property"},{"fullName":"HSAudioDevice.uid","description":"The persistent unique identifier for this device.","url":"HSAudioDevice.html#uid","kind":"property"},{"fullName":"HSAudioDevice.isOutput","description":"Whether this device has output streams (can play audio).","url":"HSAudioDevice.html#isOutput","kind":"property"},{"fullName":"HSAudioDevice.isInput","description":"Whether this device has input streams (can record audio).","url":"HSAudioDevice.html#isInput","kind":"property"},{"fullName":"HSAudioDevice.transportType","description":"The transport mechanism: \"built-in\", \"usb\", \"bluetooth\", \"bluetooth-le\", \"hdmi\", \"display-port\", \"firewire\", \"airplay\", \"avb\", \"thunderbolt\", \"virtual\", \"aggregate\", \"pci\", or \"unknown\".","url":"HSAudioDevice.html#transportType","kind":"property"},{"fullName":"HSAudioDevice.outputChannels","description":"Number of output channels, or 0 if the device has no output.","url":"HSAudioDevice.html#outputChannels","kind":"property"},{"fullName":"HSAudioDevice.inputChannels","description":"Number of input channels, or 0 if the device has no input.","url":"HSAudioDevice.html#inputChannels","kind":"property"},{"fullName":"HSAudioDevice.volume","description":"Output volume scalar in the range 0.0–1.0, or null if the device has no controllable output volume. Setting null is a no-op.","url":"HSAudioDevice.html#volume","kind":"property"},{"fullName":"HSAudioDevice.muted","description":"Whether output is muted. Always false if the device has no mutable output.","url":"HSAudioDevice.html#muted","kind":"property"},{"fullName":"HSAudioDevice.balance","description":"Output stereo balance in the range 0.0 (full left)–1.0 (full right), or null if balance control is not available.","url":"HSAudioDevice.html#balance","kind":"property"},{"fullName":"HSAudioDevice.inputVolume","description":"Input (microphone) volume scalar in the range 0.0–1.0, or null if the device has no controllable input volume.","url":"HSAudioDevice.html#inputVolume","kind":"property"},{"fullName":"HSAudioDevice.inputMuted","description":"Whether input is muted. Always false if the device has no mutable input.","url":"HSAudioDevice.html#inputMuted","kind":"property"},{"fullName":"HSAudioDevice.sampleRate","description":"The current nominal sample rate in Hz (e.g. 44100), or null if unknown.","url":"HSAudioDevice.html#sampleRate","kind":"property"},{"fullName":"HSAudioDevice.availableSampleRates","description":"All sample rates (in Hz) that this device supports. For devices that support a range, both the minimum and maximum are included.","url":"HSAudioDevice.html#availableSampleRates","kind":"property"},{"fullName":"HSAudioDevice.currentOutputDataSource()","description":"The current output data source as { id, name }, or null if unavailable.","url":"HSAudioDevice.html#currentOutputDataSource","kind":"method"},{"fullName":"HSAudioDevice.currentInputDataSource()","description":"The current input data source as { id, name }, or null if unavailable.","url":"HSAudioDevice.html#currentInputDataSource","kind":"method"},{"fullName":"HSAudioDevice.outputDataSources()","description":"All available output data sources as an array of { id, name } objects.","url":"HSAudioDevice.html#outputDataSources","kind":"method"},{"fullName":"HSAudioDevice.inputDataSources()","description":"All available input data sources as an array of { id, name } objects.","url":"HSAudioDevice.html#inputDataSources","kind":"method"},{"fullName":"HSAudioDevice.setCurrentOutputDataSource(sourceID)","description":"Select an output data source by its numeric ID.","url":"HSAudioDevice.html#setCurrentOutputDataSource","kind":"method"},{"fullName":"HSAudioDevice.setCurrentInputDataSource(sourceID)","description":"Select an input data source by its numeric ID.","url":"HSAudioDevice.html#setCurrentInputDataSource","kind":"method"},{"fullName":"HSAudioDevice.setDefaultOutputDevice()","description":"Make this device the system default output device.","url":"HSAudioDevice.html#setDefaultOutputDevice","kind":"method"},{"fullName":"HSAudioDevice.setDefaultInputDevice()","description":"Make this device the system default input device.","url":"HSAudioDevice.html#setDefaultInputDevice","kind":"method"},{"fullName":"HSAudioDevice.setDefaultEffectDevice()","description":"Make this device the system alert sound (effect) device.","url":"HSAudioDevice.html#setDefaultEffectDevice","kind":"method"},{"fullName":"HSAudioDevice.addWatcher(listener)","description":"Register a listener for a per-device property-change event.","url":"HSAudioDevice.html#addWatcher","kind":"method"},{"fullName":"HSAudioDevice.removeWatcher(listener)","description":"Remove a previously registered per-device listener.","url":"HSAudioDevice.html#removeWatcher","kind":"method"},{"fullName":"HSAXElement","description":"Object representing an Accessibility element. You should not instantiate this directly, but rather, use the hs.ax methods to create these as required.","url":"HSAXElement.html","kind":"type"},{"fullName":"HSAXElement.role","description":"The element's role (e.g., \"AXWindow\", \"AXButton\")","url":"HSAXElement.html#role","kind":"property"},{"fullName":"HSAXElement.subrole","description":"The element's subrole","url":"HSAXElement.html#subrole","kind":"property"},{"fullName":"HSAXElement.title","description":"The element's title","url":"HSAXElement.html#title","kind":"property"},{"fullName":"HSAXElement.value","description":"The element's value","url":"HSAXElement.html#value","kind":"property"},{"fullName":"HSAXElement.elementDescription","description":"The element's description","url":"HSAXElement.html#elementDescription","kind":"property"},{"fullName":"HSAXElement.isEnabled","description":"Whether the element is enabled","url":"HSAXElement.html#isEnabled","kind":"property"},{"fullName":"HSAXElement.isFocused","description":"Whether the element is focused","url":"HSAXElement.html#isFocused","kind":"property"},{"fullName":"HSAXElement.position","description":"The element's position on screen","url":"HSAXElement.html#position","kind":"property"},{"fullName":"HSAXElement.size","description":"The element's size","url":"HSAXElement.html#size","kind":"property"},{"fullName":"HSAXElement.frame","description":"The element's frame (position and size combined)","url":"HSAXElement.html#frame","kind":"property"},{"fullName":"HSAXElement.parent","description":"The element's parent","url":"HSAXElement.html#parent","kind":"property"},{"fullName":"HSAXElement.pid","description":"Get the process ID of the application that owns this element","url":"HSAXElement.html#pid","kind":"property"},{"fullName":"HSAXElement.children()","description":"The element's children","url":"HSAXElement.html#children","kind":"method"},{"fullName":"HSAXElement.childAtIndex(index)","description":"Get a specific child by index","url":"HSAXElement.html#childAtIndex","kind":"method"},{"fullName":"HSAXElement.attributeNames()","description":"Get all available attribute names","url":"HSAXElement.html#attributeNames","kind":"method"},{"fullName":"HSAXElement.attributeValue(attribute)","description":"Get the value of a specific attribute","url":"HSAXElement.html#attributeValue","kind":"method"},{"fullName":"HSAXElement.setAttributeValue(attribute, value)","description":"Set the value of a specific attribute","url":"HSAXElement.html#setAttributeValue","kind":"method"},{"fullName":"HSAXElement.isAttributeSettable(attribute)","description":"Check if an attribute is settable","url":"HSAXElement.html#isAttributeSettable","kind":"method"},{"fullName":"HSAXElement.actionNames()","description":"Get all available action names","url":"HSAXElement.html#actionNames","kind":"method"},{"fullName":"HSAXElement.performAction(action)","description":"Perform a specific action","url":"HSAXElement.html#performAction","kind":"method"},{"fullName":"HSBonjourSearch","description":"Discovers Bonjour services and domains advertised on the local network. Create via hs.bonjour.newSearch(), then call one of the find… methods. Each search type uses its own underlying NetServiceBrowser, so service and domain searches can run concurrently. Restarting any single search type stops only that browser before beginning the new one. ## Service search callback events | Event | Data | Description | |-------|------|-------------| | \"serviceFound\" | HSBonjourService | A matching service appeared | | \"serviceRemoved\" | HSBonjourService | A previously found service disappeared | | \"error\" | error string | The search failed | ## Domain search callback events | Event | Data | Description | |-------|------|-------------| | \"domainFound\" | domain string | A domain was discovered | | \"domainRemoved\" | domain string | A domain disappeared | | \"error\" | error string | The search failed |","url":"HSBonjourSearch.html","kind":"type"},{"fullName":"HSBonjourSearch.identifier","description":"A unique identifier for this search object.","url":"HSBonjourSearch.html#identifier","kind":"property"},{"fullName":"HSBonjourSearch.includesPeerToPeer","description":"Whether to search over peer-to-peer Bluetooth/Wi-Fi in addition to standard network interfaces. Defaults to false.","url":"HSBonjourSearch.html#includesPeerToPeer","kind":"property"},{"fullName":"HSBonjourSearch.findServices(type, domain, callback)","description":"Searches for services of the given type in the given domain. If a service search is already active it is stopped before starting the new one. Domain searches are unaffected. The callback receives (event, service, moreComing) — see the type documentation for the complete event table.","url":"HSBonjourSearch.html#findServices","kind":"method"},{"fullName":"HSBonjourSearch.findBrowsableDomains(callback)","description":"Searches for domains visible to this machine (browsable domains). If a browsable-domain search is already active it is stopped before starting the new one. Service and registration-domain searches are unaffected. The callback receives (event, domain, moreComing).","url":"HSBonjourSearch.html#findBrowsableDomains","kind":"method"},{"fullName":"HSBonjourSearch.findRegistrationDomains(callback)","description":"Searches for domains on which this machine can register services. If a registration-domain search is already active it is stopped before starting the new one. Service and browsable-domain searches are unaffected. The callback receives (event, domain, moreComing).","url":"HSBonjourSearch.html#findRegistrationDomains","kind":"method"},{"fullName":"HSBonjourSearch.stop()","description":"Stops all active searches. Safe to call when no search is active.","url":"HSBonjourSearch.html#stop","kind":"method"},{"fullName":"HSBonjourService","description":"A discovered Bonjour service record. Call resolve() to look up its hostname, port, and addresses. Instances are delivered by an HSBonjourSearch callback. Call resolve() to discover their hostname, port, and addresses, and optionally monitor() to watch for TXT record changes. ## Callback events | Method | Event | Extra data | |--------|-------|------------| | resolve() | \"resolved\" | _(none)_ | | resolve() | \"stopped\" | _(none)_ | | resolve() | \"error\" | error message string | | monitor() | \"txtRecord\" | updated TXT record dict |","url":"HSBonjourService.html","kind":"type"},{"fullName":"HSBonjourService.identifier","description":"A unique identifier assigned to this service object.","url":"HSBonjourService.html#identifier","kind":"property"},{"fullName":"HSBonjourService.name","description":"The service name (e.g. \"My Web Server\").","url":"HSBonjourService.html#name","kind":"property"},{"fullName":"HSBonjourService.type","description":"The service type string (e.g. \"_http._tcp.\").","url":"HSBonjourService.html#type","kind":"property"},{"fullName":"HSBonjourService.domain","description":"The mDNS domain (almost always \"local.\").","url":"HSBonjourService.html#domain","kind":"property"},{"fullName":"HSBonjourService.hostname","description":"The resolved hostname, or null before resolve() completes.","url":"HSBonjourService.html#hostname","kind":"property"},{"fullName":"HSBonjourService.port","description":"The service port. -1 until resolve() completes.","url":"HSBonjourService.html#port","kind":"property"},{"fullName":"HSBonjourService.addresses","description":"IP address strings (IPv4 and/or IPv6) populated after resolve() completes.","url":"HSBonjourService.html#addresses","kind":"property"},{"fullName":"HSBonjourService.txtRecord","description":"The TXT record as a {key: value} object, or null if none is available. Populated after resolve() completes or when updated via monitor().","url":"HSBonjourService.html#txtRecord","kind":"property"},{"fullName":"HSBonjourService.includesPeerToPeer","description":"Whether peer-to-peer Bluetooth/Wi-Fi is included in resolution.","url":"HSBonjourService.html#includesPeerToPeer","kind":"property"},{"fullName":"HSBonjourService.resolve(timeout, callback)","description":"Resolves the hostname, port, addresses, and TXT record of this service.","url":"HSBonjourService.html#resolve","kind":"method"},{"fullName":"HSBonjourService.monitor(callback)","description":"Starts monitoring the TXT record for changes. The callback fires whenever the TXT record is updated. Call stopMonitoring() to unsubscribe.","url":"HSBonjourService.html#monitor","kind":"method"},{"fullName":"HSBonjourService.stop()","description":"Stops any active resolution.","url":"HSBonjourService.html#stop","kind":"method"},{"fullName":"HSBonjourService.stopMonitoring()","description":"Stops TXT record monitoring started by monitor().","url":"HSBonjourService.html#stopMonitoring","kind":"method"},{"fullName":"HSCamera","description":"A camera device attached to the system. Obtain instances via the `hs.camera module — do not instantiate directly. ## Reading camera properties `javascript const cam = hs.camera.all()[0] console.log(cam.name + \" uid=\" + cam.uid + \" inUse=\" + cam.isInUse) ` ## Watching for in-use state changes `javascript const cam = hs.camera.all()[0] const fn = (isInUse) => { console.log(cam.name + \" is now \" + (isInUse ? \"in use\" : \"not in use\")) } cam.addWatcher(fn) // later… cam.removeWatcher(fn) ` ## Capturing a still image `javascript const cam = hs.camera.all()[0] cam.captureImage() .then(img => img.saveToFile(\"/tmp/shot.png\")) .catch(err => console.error(\"Capture failed: \" + err)) ``","url":"HSCamera.html","kind":"type"},{"fullName":"HSCamera.typeName","description":"The type name for JavaScript introspection. Always \"HSCamera\".","url":"HSCamera.html#typeName","kind":"property"},{"fullName":"HSCamera.uid","description":"The persistent unique identifier for this camera.","url":"HSCamera.html#uid","kind":"property"},{"fullName":"HSCamera.name","description":"The human-readable name of this camera (e.g. \"FaceTime HD Camera\").","url":"HSCamera.html#name","kind":"property"},{"fullName":"HSCamera.isInUse","description":"Whether this camera is currently being used by any application. Queries the underlying CoreMediaIO device state each time it is read.","url":"HSCamera.html#isInUse","kind":"property"},{"fullName":"HSCamera.addWatcher(listener)","description":"Register a listener that fires whenever this camera's in-use state changes. The listener receives one argument: a boolean that is true when the camera starts being used and false when it is released.","url":"HSCamera.html#addWatcher","kind":"method"},{"fullName":"HSCamera.removeWatcher(listener)","description":"Remove a previously registered per-camera in-use listener.","url":"HSCamera.html#removeWatcher","kind":"method"},{"fullName":"HSCamera.captureImage()","description":"Capture a still image from this camera. Camera permission must be granted via hs.permissions.requestCamera() before calling this method. The returned HSImage can be saved, displayed in a UI element, or passed to other image-processing APIs.","url":"HSCamera.html#captureImage","kind":"method"},{"fullName":"HSChooser","description":"A keyboard-driven floating chooser panel. Create via hs.chooser.create(). Configure choices, set callbacks, then call .show(). ## Choice format Each choice is a plain object with required text and optional subText, image, valid, and contextMenu fields. All other fields are passed through to the onSelect callback unchanged. The contextMenu array defines per-row right-click menu entries. Each entry is either ``javascript { text: \"Open Safari\", subText: \"com.apple.Safari\", image: HSImage.fromAppBundle(\"com.apple.Safari\"), valid: true, myData: 42, contextMenu: [ { title: \"Open\", action: () => hs.urlevent.openURL(\"https://apple.com\") }, { type: \"divider\" }, { title: \"Copy bundle ID\", action: () => hs.pasteboard.writeString(\"com.apple.Safari\") } ] } `` ## Keyboard shortcuts","url":"HSChooser.html","kind":"type"},{"fullName":"HSChooser.typeName","description":"Read-only type identifier.","url":"HSChooser.html#typeName","kind":"property"},{"fullName":"HSChooser.identifier","description":"Stable UUID string for this chooser instance.","url":"HSChooser.html#identifier","kind":"property"},{"fullName":"HSChooser.query","description":"The current text in the search field. Setting this from JS updates the display but does not invoke the onQueryChange callback.","url":"HSChooser.html#query","kind":"property"},{"fullName":"HSChooser.placeholder","description":"Placeholder text shown in the empty search field (default: \"Search...\").","url":"HSChooser.html#placeholder","kind":"property"},{"fullName":"HSChooser.searchSubText","description":"Whether searches match against subText in addition to text (default: false). Only applies when a static choices array is provided.","url":"HSChooser.html#searchSubText","kind":"property"},{"fullName":"HSChooser.enableDefaultForQuery","description":"When true and the query is non-empty but there are no matching choices, onSelect is called with { text: } instead of null (default: false).","url":"HSChooser.html#enableDefaultForQuery","kind":"property"},{"fullName":"HSChooser.selectedRow","description":"The zero-based index of the currently highlighted row (-1 when empty).","url":"HSChooser.html#selectedRow","kind":"property"},{"fullName":"HSChooser.width","description":"Width of the chooser as a fraction of the screen width (default: 0.5 = 50 %).","url":"HSChooser.html#width","kind":"property"},{"fullName":"HSChooser.visibleRows","description":"Maximum number of rows visible at once without scrolling (default: 10).","url":"HSChooser.html#visibleRows","kind":"property"},{"fullName":"HSChooser.isVisible","description":"true if the chooser panel is currently on screen.","url":"HSChooser.html#isVisible","kind":"property"},{"fullName":"HSChooser.onSelect","description":"Called when the user confirms a selection, or null to remove the handler. The argument is the chosen row object (the original dict you passed to setChoices, with text, subText, image, valid, and any custom fields intact). The argument is null when dismissed (Escape).","url":"HSChooser.html#onSelect","kind":"property"},{"fullName":"HSChooser.onQueryChange","description":"Called on every keystroke with the new query string, or null to remove the handler. Use this to debounce expensive searches or trigger async data fetching.","url":"HSChooser.html#onQueryChange","kind":"property"},{"fullName":"HSChooser.onShow","description":"Called after the panel becomes visible, or null to remove the handler.","url":"HSChooser.html#onShow","kind":"property"},{"fullName":"HSChooser.onHide","description":"Called after the panel is hidden (for any reason: selection, Escape, or hide()), or null to remove the handler.","url":"HSChooser.html#onHide","kind":"property"},{"fullName":"HSChooser.onInvalid","description":"Called when the user activates a row whose valid field is false, or null to remove the handler. The chooser stays open; the argument is the row dict (same shape as onSelect). If unset, activating an invalid row is silently ignored.","url":"HSChooser.html#onInvalid","kind":"property"},{"fullName":"HSChooser.setChoices(choices)","description":"on show. The function is responsible for filtering; the chooser displays all items it returns.","url":"HSChooser.html#setChoices","kind":"method"},{"fullName":"HSChooser.refreshChoices()","description":"Re-apply filtering (static choices) or re-invoke the choices function (dynamic). Call after updating an external data source in an async onQueryChange handler.","url":"HSChooser.html#refreshChoices","kind":"method"},{"fullName":"HSChooser.show()","description":"Show the chooser.","url":"HSChooser.html#show","kind":"method"},{"fullName":"HSChooser.hide()","description":"Hide the chooser without making a selection. Restores focus to the previously active window.","url":"HSChooser.html#hide","kind":"method"},{"fullName":"HSChooser.select(row)","description":"Programmatically confirm a selection. Omit row to confirm the currently highlighted row. Fires onSelect (or onInvalid for rows with valid: false) and hides the chooser.","url":"HSChooser.html#select","kind":"method"},{"fullName":"HSChooser.selectedRowContents(row)","description":"Returns the dict for the highlighted row, or for a specific row by index. Returns null if the index is out of range or no choices are set.","url":"HSChooser.html#selectedRowContents","kind":"method"},{"fullName":"HSEventTap","description":"An event tap watcher that intercepts input events from the system. Obtain instances via hs.eventtap.addWatcher() — do not instantiate directly. ## Monitoring keyboard events ``js const tap = hs.eventtap.addWatcher([hs.eventtap.eventTypes.keyDown], (event) => { console.log(\"Key pressed: \" + event.keyCode) }) ``","url":"HSEventTap.html","kind":"type"},{"fullName":"HSEventTap.identifier","description":"A unique identifier for this tap","url":"HSEventTap.html#identifier","kind":"property"},{"fullName":"HSEventTap.listenOnly","description":"Whether this tap was created as listen-only (events are observed but never modified or suppressed)","url":"HSEventTap.html#listenOnly","kind":"property"},{"fullName":"HSEventTap.start()","description":"Start receiving events. Requires Accessibility permission.","url":"HSEventTap.html#start","kind":"method"},{"fullName":"HSEventTap.stop()","description":"Stop receiving events","url":"HSEventTap.html#stop","kind":"method"},{"fullName":"HSEventTap.setCallback(callback)","description":"Replace the callback function","url":"HSEventTap.html#setCallback","kind":"method"},{"fullName":"HSEventTap.isEnabled()","description":"Whether this tap is currently active","url":"HSEventTap.html#isEnabled","kind":"method"},{"fullName":"HSEventTap.isCreated()","description":"Whether this tap has been registered with macOS","url":"HSEventTap.html#isCreated","kind":"method"},{"fullName":"HSEventTapEvent","description":"An input event captured or constructed by hs.eventtap. Objects of this type are passed to event tap callbacks and can also be created directly via the factory methods on hs.eventtap. Properties can be inspected and modified before the event is passed through or posted back to the system.","url":"HSEventTapEvent.html","kind":"type"},{"fullName":"HSEventTapEvent.typeName","description":"Type name for introspection","url":"HSEventTapEvent.html#typeName","kind":"property"},{"fullName":"HSEventTapEvent.type","description":"The numeric event type, matching a value in hs.eventtap.eventTypes","url":"HSEventTapEvent.html#type","kind":"property"},{"fullName":"HSEventTapEvent.keyCode","description":"The virtual key code for keyboard events (get/set)","url":"HSEventTapEvent.html#keyCode","kind":"property"},{"fullName":"HSEventTapEvent.rawFlags","description":"The raw modifier flags bitmask (get/set). Use values from hs.eventtap.modifierFlags.","url":"HSEventTapEvent.html#rawFlags","kind":"property"},{"fullName":"HSEventTapEvent.flags","description":"An array of active modifier key names (e.g. [\"cmd\", \"shift\"]). When a device-specific modifier is detected, both the generic and side-specific names are included — e.g. pressing the left Command key yields [\"cmd\", \"leftCmd\"].","url":"HSEventTapEvent.html#flags","kind":"property"},{"fullName":"HSEventTapEvent.location","description":"The event's screen position as {x, y} in Hammerspoon screen coordinates (top-left origin of primary display, y increases downward, matching hs.screen).","url":"HSEventTapEvent.html#location","kind":"property"},{"fullName":"HSEventTapEvent.buttonNumber","description":"The mouse button number for mouse events (0=left, 1=right, 2=middle)","url":"HSEventTapEvent.html#buttonNumber","kind":"property"},{"fullName":"HSEventTapEvent.scrollingDeltaX","description":"The horizontal scroll delta for scroll wheel events","url":"HSEventTapEvent.html#scrollingDeltaX","kind":"property"},{"fullName":"HSEventTapEvent.scrollingDeltaY","description":"The vertical scroll delta for scroll wheel events","url":"HSEventTapEvent.html#scrollingDeltaY","kind":"property"},{"fullName":"HSEventTapEvent.characters","description":"The Unicode characters produced by this keyboard event, or null for non-keyboard events","url":"HSEventTapEvent.html#characters","kind":"property"},{"fullName":"HSEventTapEvent.duplicate()","description":"Create an independent copy of this event","url":"HSEventTapEvent.html#duplicate","kind":"method"},{"fullName":"HSEventTapEvent.post(app)","description":"Post this event to the HID event stream, optionally targeting a specific application. When app is omitted or null, the event is posted to the global HID stream and delivered by the OS as if a real input device generated it. When an application is provided, the event is delivered directly to that process by PID.","url":"HSEventTapEvent.html#post","kind":"method"},{"fullName":"HSEventTapHotkey","description":"A keyboard shortcut binding backed by an event tap. Supports fn modifier and left/right modifier key distinction. Obtain instances via hs.eventtap.bindHotkey() — do not instantiate directly.","url":"HSEventTapHotkey.html","kind":"type"},{"fullName":"HSEventTapHotkey.callbackPressed","description":"The callback function to be called when the hotkey is pressed, or null to remove it","url":"HSEventTapHotkey.html#callbackPressed","kind":"property"},{"fullName":"HSEventTapHotkey.callbackReleased","description":"The callback function to be called when the hotkey is released, or null to remove it","url":"HSEventTapHotkey.html#callbackReleased","kind":"property"},{"fullName":"HSEventTapHotkey.enable()","description":"Enable the hotkey","url":"HSEventTapHotkey.html#enable","kind":"method"},{"fullName":"HSEventTapHotkey.disable()","description":"Disable the hotkey","url":"HSEventTapHotkey.html#disable","kind":"method"},{"fullName":"HSEventTapHotkey.isEnabled()","description":"Check if the hotkey is currently enabled","url":"HSEventTapHotkey.html#isEnabled","kind":"method"},{"fullName":"HSVolumeWatcher","description":"A volume event watcher that monitors filesystem mount/unmount/rename events. Create via hs.fs.addVolumeWatcher(). Set a callback with setCallback(), then call start() to begin receiving events. | Event | Info keys | |-------|-----------| | \"didMount\" | path: string | | \"didUnmount\" | path: string | | \"willUnmount\" | path: string | | \"didRename\" | path: string, name: string, oldPath?: string, oldName?: string |","url":"HSVolumeWatcher.html","kind":"type"},{"fullName":"HSVolumeWatcher.identifier","description":"The unique identifier assigned to this watcher.","url":"HSVolumeWatcher.html#identifier","kind":"property"},{"fullName":"HSVolumeWatcher.start()","description":"Starts monitoring volume events.","url":"HSVolumeWatcher.html#start","kind":"method"},{"fullName":"HSVolumeWatcher.stop()","description":"Stops monitoring volume events.","url":"HSVolumeWatcher.html#stop","kind":"method"},{"fullName":"HSVolumeWatcher.setCallback(fn)","description":"Sets the callback function invoked when volume events occur.","url":"HSVolumeWatcher.html#setCallback","kind":"method"},{"fullName":"HSVolumeWatcher.destroy()","description":"Stops the watcher and releases all resources. Called automatically during shutdown.","url":"HSVolumeWatcher.html#destroy","kind":"method"},{"fullName":"HSHotkey","description":"Object representing a system-wide hotkey. You should not create these objects directly, but rather, use the methods in hs.hotkey to instantiate these.","url":"HSHotkey.html","kind":"type"},{"fullName":"HSHotkey.callbackPressed","description":"The callback function to be called when the hotkey is pressed, or null to remove it","url":"HSHotkey.html#callbackPressed","kind":"property"},{"fullName":"HSHotkey.callbackReleased","description":"The callback function to be called when the hotkey is released, or null to remove it","url":"HSHotkey.html#callbackReleased","kind":"property"},{"fullName":"HSHotkey.enable()","description":"Enable the hotkey","url":"HSHotkey.html#enable","kind":"method"},{"fullName":"HSHotkey.disable()","description":"Disable the hotkey","url":"HSHotkey.html#disable","kind":"method"},{"fullName":"HSHotkey.isEnabled()","description":"Check if the hotkey is currently enabled","url":"HSHotkey.html#isEnabled","kind":"method"},{"fullName":"HSHotkey.destroy()","description":"Disable and permanently remove this hotkey, releasing all associated resources","url":"HSHotkey.html#destroy","kind":"method"},{"fullName":"HSWebSocket","description":"A WebSocket client connection created by hs.http.openWebSocket(). The connection opens immediately when returned. Use the chainable setter methods to register event callbacks, then call send() to transmit messages. Do not instantiate HSWebSocket directly — use hs.http.openWebSocket().","url":"HSWebSocket.html","kind":"type"},{"fullName":"HSWebSocket.identifier","description":"A unique identifier for this connection (UUID string).","url":"HSWebSocket.html#identifier","kind":"property"},{"fullName":"HSWebSocket.readyState","description":"The current connection state.","url":"HSWebSocket.html#readyState","kind":"property"},{"fullName":"HSWebSocket.setOpenCallback(callback)","description":"Set the callback invoked when the connection is established.","url":"HSWebSocket.html#setOpenCallback","kind":"method"},{"fullName":"HSWebSocket.setMessageCallback(callback)","description":"Set the callback invoked when a text message is received from the server.","url":"HSWebSocket.html#setMessageCallback","kind":"method"},{"fullName":"HSWebSocket.setCloseCallback(callback)","description":"Set the callback invoked when the connection is closed by the remote end.","url":"HSWebSocket.html#setCloseCallback","kind":"method"},{"fullName":"HSWebSocket.setErrorCallback(callback)","description":"Set the callback invoked when a connection or protocol error occurs.","url":"HSWebSocket.html#setErrorCallback","kind":"method"},{"fullName":"HSWebSocket.send(message)","description":"Send a text message to the server. The connection must be open (readyState === 1).","url":"HSWebSocket.html#send","kind":"method"},{"fullName":"HSWebSocket.close()","description":"Close the WebSocket connection with a normal closure code (1000). If a close callback is registered, it is invoked synchronously.","url":"HSWebSocket.html#close","kind":"method"},{"fullName":"HSWebSocket.destroy()","description":"Destroy this WebSocket, releasing all resources without invoking callbacks. Called automatically by hs.http.shutdown(). After destroy(), do not use this object.","url":"HSWebSocket.html#destroy","kind":"method"},{"fullName":"HSHTTPServer","description":"An HTTP server instance created by hs.httpserver.create(). Configure with chainable setter methods, then call start() to begin accepting connections. The server supports synchronous and async (Promise-returning) request callbacks, optional static file serving, HTTP Basic authentication, Bonjour advertisement, and TLS via PKCS#12. Do not instantiate HSHTTPServer directly — use hs.httpserver.create().","url":"HSHTTPServer.html","kind":"type"},{"fullName":"HSHTTPServer.identifier","description":"A unique identifier for this server instance (UUID string).","url":"HSHTTPServer.html#identifier","kind":"property"},{"fullName":"HSHTTPServer.setPort(port)","description":"Set the TCP port to listen on. Must be called before start(). Pass 0 to let the OS assign an available port (use getPort() after start() to discover it).","url":"HSHTTPServer.html#setPort","kind":"method"},{"fullName":"HSHTTPServer.setInterface(iface)","description":"Set the network interface to listen on. Pass null to listen on all interfaces (the default). Pass \"localhost\" or \"loopback\" to restrict to the loopback interface only.","url":"HSHTTPServer.html#setInterface","kind":"method"},{"fullName":"HSHTTPServer.setPassword(password)","description":"Set a password required for Basic authentication. When set, every request must supply an Authorization: Basic header with any username and the configured password. Pass null to disable authentication.","url":"HSHTTPServer.html#setPassword","kind":"method"},{"fullName":"HSHTTPServer.setMaxBodySize(size)","description":"Set the maximum allowed incoming request body size in bytes. Requests with a body exceeding this limit receive a 413 response. Defaults to 10 MB.","url":"HSHTTPServer.html#setMaxBodySize","kind":"method"},{"fullName":"HSHTTPServer.setName(name)","description":"Set the Bonjour service name advertised on the local network. Only used when Bonjour is enabled via setBonjour(true).","url":"HSHTTPServer.html#setName","kind":"method"},{"fullName":"HSHTTPServer.setBonjour(enable)","description":"Enable or disable Bonjour advertisement of this server on the local network.","url":"HSHTTPServer.html#setBonjour","kind":"method"},{"fullName":"HSHTTPServer.setCallback(callback)","description":"Set the request handler callback. If the callback returns null or undefined, the server falls through to static file serving (if a document root is set), or responds with 404.","url":"HSHTTPServer.html#setCallback","kind":"method"},{"fullName":"HSHTTPServer.setDocumentRoot(path)","description":"Set the filesystem path to serve static files from. When a document root is set, requests not handled by the callback are served as static files from this directory. Pass null to disable static file serving.","url":"HSHTTPServer.html#setDocumentRoot","kind":"method"},{"fullName":"HSHTTPServer.setDirectoryIndex(files)","description":"Set the list of index filenames checked when a directory is requested. Defaults to [\"index.html\", \"index.htm\"]. Files are checked in order.","url":"HSHTTPServer.html#setDirectoryIndex","kind":"method"},{"fullName":"HSHTTPServer.setAllowDirectoryListing(allow)","description":"Enable or disable directory listing for requests that map to a directory with no index file. When disabled (the default), directory requests without an index file return 403.","url":"HSHTTPServer.html#setAllowDirectoryListing","kind":"method"},{"fullName":"HSHTTPServer.setTLSFromPKCS12(path, password)","description":"Configure TLS using a PKCS#12 (.p12) identity file. When TLS is configured, the server accepts HTTPS connections. The .p12 file must contain both the certificate and the private key.","url":"HSHTTPServer.html#setTLSFromPKCS12","kind":"method"},{"fullName":"HSHTTPServer.start()","description":"Start the server and begin accepting connections. The server must be configured before calling start(). To restart the server with new settings, call stop() followed by start().","url":"HSHTTPServer.html#start","kind":"method"},{"fullName":"HSHTTPServer.stop()","description":"Stop the server and close all connections.","url":"HSHTTPServer.html#stop","kind":"method"},{"fullName":"HSHTTPServer.destroy()","description":"Destroy this server, releasing all resources. After calling destroy(), the server object should not be used.","url":"HSHTTPServer.html#destroy","kind":"method"},{"fullName":"HSHTTPServer.getPort()","description":"Get the TCP port the server is currently listening on. Returns 0 if the server is not running.","url":"HSHTTPServer.html#getPort","kind":"method"},{"fullName":"HSHTTPServer.getName()","description":"Get the configured Bonjour service name.","url":"HSHTTPServer.html#getName","kind":"method"},{"fullName":"HSHTTPServer.getInterface()","description":"Get the configured network interface, or null if listening on all interfaces.","url":"HSHTTPServer.html#getInterface","kind":"method"},{"fullName":"HSHTTPServer.setWebSocketCallback(path, callback)","description":"Register a WebSocket handler for a URL path. When a client connects and performs a WebSocket upgrade handshake on path, the callback is invoked with three arguments: event (string), connection (HSWebSocketConnection), and message (string). Events: Pass null to remove the WebSocket handler for the path.","url":"HSHTTPServer.html#setWebSocketCallback","kind":"method"},{"fullName":"HSWebSocketConnection","description":"A WebSocket connection to a single client, passed to the callback registered with server.setWebSocketCallback(). Use send() to push messages to the connected client and close() to end the connection. Do not instantiate HSWebSocketConnection directly — it is created by the server when a client performs a WebSocket upgrade.","url":"HSWebSocketConnection.html","kind":"type"},{"fullName":"HSWebSocketConnection.identifier","description":"A unique identifier for this connection (UUID string).","url":"HSWebSocketConnection.html#identifier","kind":"property"},{"fullName":"HSWebSocketConnection.send(message)","description":"Send a text message to the connected WebSocket client.","url":"HSWebSocketConnection.html#send","kind":"method"},{"fullName":"HSWebSocketConnection.close()","description":"Close the WebSocket connection to the client. Sends a WebSocket close frame and cancels the underlying TCP connection.","url":"HSWebSocketConnection.html#close","kind":"method"},{"fullName":"HSWebSocketConnection.destroy()","description":"Destroy this connection object, releasing all resources.","url":"HSWebSocketConnection.html#destroy","kind":"method"},{"fullName":"HSLocationWatcher","description":"An independent location tracking object. Create via hs.location.addWatcher(). Call start() to begin receiving updates, and set a callback to handle them. | Event | Data | |-------|------| | \"location\" | a locationTable | | \"error\" | an error message string | | \"authorizationChanged\" | the new status string (\"authorized\", \"denied\", \"restricted\", \"notDetermined\") |","url":"HSLocationWatcher.html","kind":"type"},{"fullName":"HSLocationWatcher.identifier","description":"The unique identifier assigned to this watcher.","url":"HSLocationWatcher.html#identifier","kind":"property"},{"fullName":"HSLocationWatcher.distanceFilter","description":"The minimum distance in metres the device must move before a new update is delivered. Defaults to kCLDistanceFilterNone (all movements reported).","url":"HSLocationWatcher.html#distanceFilter","kind":"property"},{"fullName":"HSLocationWatcher.start()","description":"Starts location updates. The callback must be set first.","url":"HSLocationWatcher.html#start","kind":"method"},{"fullName":"HSLocationWatcher.stop()","description":"Stops location updates.","url":"HSLocationWatcher.html#stop","kind":"method"},{"fullName":"HSLocationWatcher.setCallback(fn)","description":"Sets the callback function invoked when location events occur.","url":"HSLocationWatcher.html#setCallback","kind":"method"},{"fullName":"HSLocationWatcher.location()","description":"Returns the most recently received location, or null if none yet.","url":"HSLocationWatcher.html#location","kind":"method"},{"fullName":"HSMenuBarItem","description":"Object representing a macOS system menu bar item. Create instances with hs.menubar.create().","url":"HSMenuBarItem.html","kind":"type"},{"fullName":"HSMenuBarItem.title","description":"Get or set the menu item's title.","url":"HSMenuBarItem.html#title","kind":"property"},{"fullName":"HSMenuBarItem.setIcon(image)","description":"Set the icon displayed in the menu bar","url":"HSMenuBarItem.html#setIcon","kind":"method"},{"fullName":"HSMenuBarItem.setTooltip(tooltip)","description":"Set the tooltip shown when hovering over the menu bar item","url":"HSMenuBarItem.html#setTooltip","kind":"method"},{"fullName":"HSMenuBarItem.setClickCallback(fn)","description":"Set a callback invoked when the item is clicked (only fires when no menu is set)","url":"HSMenuBarItem.html#setClickCallback","kind":"method"},{"fullName":"HSMenuBarItem.setMenu(menuOrFn)","description":"Set the menu for this item. Pass an array of menu item objects for a static menu, or a function that returns an array for a dynamic menu populated each time it opens.","url":"HSMenuBarItem.html#setMenu","kind":"method"},{"fullName":"HSMenuBarItem.hide()","description":"Remove this item from the menu bar. The item is retained and can be shown again with show().","url":"HSMenuBarItem.html#hide","kind":"method"},{"fullName":"HSMenuBarItem.show()","description":"Show this item in the menu bar.","url":"HSMenuBarItem.html#show","kind":"method"},{"fullName":"HSMenuBarItem.isVisible()","description":"Check if this item is currently visible in the menu bar.","url":"HSMenuBarItem.html#isVisible","kind":"method"},{"fullName":"HSMenuBarItem.destroy()","description":"Permanently remove this item from the menu bar and release all resources. After calling destroy(), the item is no longer usable. This is called automatically on hs.reload(). Use hide() instead if you only want to temporarily remove the item without freeing it.","url":"HSMenuBarItem.html#destroy","kind":"method"},{"fullName":"HSNetworkConfigurationWatcher","description":"A watcher for System Configuration dynamic store key changes. Create with hs.network.configurationWatcher().","url":"HSNetworkConfigurationWatcher.html","kind":"type"},{"fullName":"HSNetworkConfigurationWatcher.typeName","description":"Always \"HSNetworkConfigurationWatcher\".","url":"HSNetworkConfigurationWatcher.html#typeName","kind":"property"},{"fullName":"HSNetworkConfigurationWatcher.setKeys(keys, pattern)","description":"Specifies which dynamic store keys (or key patterns) to watch for changes. Must be called before start(). Each element of keys is treated as a string literal when pattern is false (the default), or as a regular expression when pattern is true. Calling setKeys again replaces the previous set of watched keys.","url":"HSNetworkConfigurationWatcher.html#setKeys","kind":"method"},{"fullName":"HSNetworkConfigurationWatcher.setCallback(callback)","description":"Sets the callback invoked when a watched key changes. The callback receives (watcher, changedKeys) where changedKeys is an array of key strings that changed since the last notification. Call hs.network.configurationStore() inside the callback to read the updated values.","url":"HSNetworkConfigurationWatcher.html#setCallback","kind":"method"},{"fullName":"HSNetworkConfigurationWatcher.start()","description":"Starts watching for dynamic store changes. The callback registered with setCallback() will be invoked whenever a key matching the patterns registered with setKeys() changes. Call setKeys() and setCallback() before calling start().","url":"HSNetworkConfigurationWatcher.html#start","kind":"method"},{"fullName":"HSNetworkConfigurationWatcher.stop()","description":"Stops watching for dynamic store changes. The callback will no longer be invoked. Call start() again to resume monitoring.","url":"HSNetworkConfigurationWatcher.html#stop","kind":"method"},{"fullName":"HSNetworkPing","description":"Object representing an active or completed ICMP ping operation. Create instances with hs.network.ping().","url":"HSNetworkPing.html","kind":"type"},{"fullName":"HSNetworkPing.typeName","description":"Always \"HSNetworkPing\".","url":"HSNetworkPing.html#typeName","kind":"property"},{"fullName":"HSNetworkPing.address","description":"The resolved IP address of the target, or \"\" if DNS has not yet completed.","url":"HSNetworkPing.html#address","kind":"property"},{"fullName":"HSNetworkPing.server","description":"The hostname or IP address string originally passed to hs.network.ping().","url":"HSNetworkPing.html#server","kind":"property"},{"fullName":"HSNetworkPing.sent","description":"The number of ICMP Echo Requests sent so far.","url":"HSNetworkPing.html#sent","kind":"property"},{"fullName":"HSNetworkPing.count","description":"The total number of ICMP Echo Requests to send. May be increased while the ping is running provided the new value is greater than the number already sent.","url":"HSNetworkPing.html#count","kind":"property"},{"fullName":"HSNetworkPing.isRunning","description":"true while the ping is actively sending and waiting for replies.","url":"HSNetworkPing.html#isRunning","kind":"property"},{"fullName":"HSNetworkPing.isPaused","description":"true when the ping has been suspended with pause().","url":"HSNetworkPing.html#isPaused","kind":"property"},{"fullName":"HSNetworkPing.packets(sequenceNumber)","description":"Returns packet statistics for all sent packets, or for a single packet by its zero-based sequence number.","url":"HSNetworkPing.html#packets","kind":"method"},{"fullName":"HSNetworkPing.summary()","description":"Returns a human-readable summary of the ping results in standard ping format.","url":"HSNetworkPing.html#summary","kind":"method"},{"fullName":"HSNetworkPing.pause()","description":"Suspends the ping. No further packets are sent until resume() is called.","url":"HSNetworkPing.html#pause","kind":"method"},{"fullName":"HSNetworkPing.resume()","description":"Resumes a paused ping, continuing from where it left off.","url":"HSNetworkPing.html#resume","kind":"method"},{"fullName":"HSNetworkPing.cancel()","description":"Immediately stops the ping, firing the \"didFinish\" callback with statistics collected so far.","url":"HSNetworkPing.html#cancel","kind":"method"},{"fullName":"HSNetworkPing.setCallback(callback)","description":"Replaces the ping's callback function.","url":"HSNetworkPing.html#setCallback","kind":"method"},{"fullName":"HSNetworkReachability","description":"An active or inactive network reachability monitor. Create with hs.network.reachability*().","url":"HSNetworkReachability.html","kind":"type"},{"fullName":"HSNetworkReachability.typeName","description":"Always \"HSNetworkReachability\".","url":"HSNetworkReachability.html#typeName","kind":"property"},{"fullName":"HSNetworkReachability.status()","description":"Returns the current reachability flags as a numeric bitmask. Compare against constants in hs.network.reachabilityFlags. Returns 0 if the network is currently unreachable.","url":"HSNetworkReachability.html#status","kind":"method"},{"fullName":"HSNetworkReachability.statusString()","description":"Returns a human-readable summary of the current reachability flags. The string contains 8 characters in order: t (transient/expensive), R (reachable), c (connectionRequired), C (connectionOnTraffic — always -), i (interventionRequired/constrained), D (connectionOnDemand — always -), l (isLocalAddress — always -), d (isDirect). A letter appears when that flag is set; - appears when it is clear.","url":"HSNetworkReachability.html#statusString","kind":"method"},{"fullName":"HSNetworkReachability.setCallback(callback)","description":"Replaces the callback invoked when reachability changes. The callback receives (reachability, flags) where flags is the same numeric bitmask as returned by status(). Call start() after setCallback() to begin monitoring.","url":"HSNetworkReachability.html#setCallback","kind":"method"},{"fullName":"HSNetworkReachability.start()","description":"Starts monitoring for reachability changes. After calling start(), the callback registered with setCallback() is invoked whenever the reachability status changes.","url":"HSNetworkReachability.html#start","kind":"method"},{"fullName":"HSNetworkReachability.stop()","description":"Stops monitoring for reachability changes. The callback will no longer be invoked. Call start() again to resume monitoring.","url":"HSNetworkReachability.html#stop","kind":"method"},{"fullName":"HSNotification","description":"A notification created by hs.notify.new(). Call .send() to deliver it to macOS Notification Center. You can hold a reference to the object and call .withdraw() later to remove it.","url":"HSNotification.html","kind":"type"},{"fullName":"HSNotification.identifier","description":"The unique identifier assigned to this notification. Use it to correlate with system notification APIs if needed.","url":"HSNotification.html#identifier","kind":"property"},{"fullName":"HSNotification.send()","description":"Deliver this notification immediately to Notification Center.","url":"HSNotification.html#send","kind":"method"},{"fullName":"HSNotification.withdraw()","description":"Remove this notification from Notification Center (if delivered) or cancel it (if pending).","url":"HSNotification.html#withdraw","kind":"method"},{"fullName":"HSOCRObservation","description":"A single region of text recognized in an image. Instances are delivered inside the observations array of an HSOCRResult. Each observation represents a discrete text run found in the source image, along with a confidence score and a normalized bounding box. (0, 0) is the top-left corner of the image and (1, 1) is the bottom-right. This matches the convention used by most image-processing tools and differs from Vision's internal bottom-left-origin system (the conversion is automatic).","url":"HSOCRObservation.html","kind":"type"},{"fullName":"HSOCRObservation.typeName","description":"The Swift type name, for JavaScript introspection.","url":"HSOCRObservation.html#typeName","kind":"property"},{"fullName":"HSOCRObservation.text","description":"The recognized text string for this observation.","url":"HSOCRObservation.html#text","kind":"property"},{"fullName":"HSOCRObservation.confidence","description":"Recognition confidence in the range 0.0 (uncertain) to 1.0 (certain). Use minimumConfidence in the options passed to recognizeText() to pre-filter observations below a threshold rather than filtering here.","url":"HSOCRObservation.html#confidence","kind":"property"},{"fullName":"HSOCRObservation.bounds","description":"Normalized bounding box of this observation in the source image, as an HSRect. All values are in the range 0–1 with top-left origin ((0, 0) = top-left corner, (1, 1) = bottom-right corner). Use bounds.x, bounds.y, bounds.w, and bounds.h to access the components.","url":"HSOCRObservation.html#bounds","kind":"property"},{"fullName":"HSOCRResult","description":"The result of a text recognition operation on an image. An HSOCRResult is returned by hs.ocr.recognizeText() and bundles the full recognized text together with an array of per-region observations, each carrying its own confidence score and bounding box.","url":"HSOCRResult.html","kind":"type"},{"fullName":"HSOCRResult.typeName","description":"The Swift type name, for JavaScript introspection.","url":"HSOCRResult.html#typeName","kind":"property"},{"fullName":"HSOCRResult.text","description":"The full recognized text from the image, with each observation's text joined by newlines in the order Vision returned them. Use this when you only need the raw text and don't care about bounding boxes or per-region confidence scores.","url":"HSOCRResult.html#text","kind":"property"},{"fullName":"HSOCRResult.observations","description":"The individual text observations that make up this result. Each entry in the array is an HSOCRObservation with its own text, confidence, and bounds properties. Observations are returned in the order Vision produced them (typically top-to-bottom, left-to-right, but this is image-dependent).","url":"HSOCRResult.html#observations","kind":"property"},{"fullName":"HSScreen","description":"An object representing a single display attached to the system. ## Coordinate system All geometry is returned in Hammerspoon screen coordinates: the origin (0, 0) is at the top-left of the primary display, and y increases downward. This matches Hammerspoon v1 and is the inverse of the raw macOS/CoreGraphics convention. ## Examples ``javascript const s = hs.screen.main(); console.log(s.name); // e.g. \"Built-in Retina Display\" console.log(s.frame.w); // usable width in points","url":"HSScreen.html","kind":"type"},{"fullName":"HSScreen.id","description":"Unique display identifier (matches CGDirectDisplayID).","url":"HSScreen.html#id","kind":"property"},{"fullName":"HSScreen.name","description":"The manufacturer-assigned localized display name.","url":"HSScreen.html#name","kind":"property"},{"fullName":"HSScreen.uuid","description":"The display's UUID string.","url":"HSScreen.html#uuid","kind":"property"},{"fullName":"HSScreen.frame","description":"The usable screen area in Hammerspoon coordinates, excluding the menu bar and Dock.","url":"HSScreen.html#frame","kind":"property"},{"fullName":"HSScreen.fullFrame","description":"The full screen area in Hammerspoon coordinates, including menu bar and Dock regions.","url":"HSScreen.html#fullFrame","kind":"property"},{"fullName":"HSScreen.position","description":"The screen's top-left corner in global Hammerspoon coordinates.","url":"HSScreen.html#position","kind":"property"},{"fullName":"HSScreen.mode","description":"The currently active display mode. An object with keys: width, height, scale, frequency.","url":"HSScreen.html#mode","kind":"property"},{"fullName":"HSScreen.availableModes","description":"All display modes supported by this screen. Each element has keys: width, height, scale, frequency.","url":"HSScreen.html#availableModes","kind":"property"},{"fullName":"HSScreen.rotation","description":"The current screen rotation in degrees (0, 90, 180, or 270). Assign one of 0, 90, 180, or 270 to rotate the display.","url":"HSScreen.html#rotation","kind":"property"},{"fullName":"HSScreen.desktopImage","description":"The URL string of the current desktop background image for this screen, or null. Assign a new absolute file path or file:// URL string to change the wallpaper.","url":"HSScreen.html#desktopImage","kind":"property"},{"fullName":"HSScreen.ambientLight","description":"The ambient light level measured by this display's built-in sensor, in lux. Returns null if the display does not have an ambient light sensor or if the reading is currently unavailable.","url":"HSScreen.html#ambientLight","kind":"property"},{"fullName":"HSScreen.setMode(width, height, scale, frequency)","description":"Switch to the given display mode. Pass 0 for scale or frequency to match any value.","url":"HSScreen.html#setMode","kind":"method"},{"fullName":"HSScreen.snapshot()","description":"Capture the current contents of this screen as an image. Requires Screen Recording permission.","url":"HSScreen.html#snapshot","kind":"method"},{"fullName":"HSScreen.next()","description":"The next screen in hs.screen.all() order, wrapping around.","url":"HSScreen.html#next","kind":"method"},{"fullName":"HSScreen.previous()","description":"The previous screen in hs.screen.all() order, wrapping around.","url":"HSScreen.html#previous","kind":"method"},{"fullName":"HSScreen.toEast()","description":"The nearest screen whose left edge is at or beyond this screen's right edge, or null.","url":"HSScreen.html#toEast","kind":"method"},{"fullName":"HSScreen.toWest()","description":"The nearest screen whose right edge is at or before this screen's left edge, or null.","url":"HSScreen.html#toWest","kind":"method"},{"fullName":"HSScreen.toNorth()","description":"The nearest screen that is physically above this screen, or null.","url":"HSScreen.html#toNorth","kind":"method"},{"fullName":"HSScreen.toSouth()","description":"The nearest screen that is physically below this screen, or null.","url":"HSScreen.html#toSouth","kind":"method"},{"fullName":"HSScreen.setOrigin(x, y)","description":"Move this screen so its top-left corner is at the given position in global Hammerspoon coordinates.","url":"HSScreen.html#setOrigin","kind":"method"},{"fullName":"HSScreen.setPrimary()","description":"Designate this screen as the primary display (moves the menu bar here).","url":"HSScreen.html#setPrimary","kind":"method"},{"fullName":"HSScreen.mirrorOf(screen)","description":"Configure this screen to mirror another screen.","url":"HSScreen.html#mirrorOf","kind":"method"},{"fullName":"HSScreen.mirrorStop()","description":"Stop mirroring, restoring this screen to an independent display.","url":"HSScreen.html#mirrorStop","kind":"method"},{"fullName":"HSScreen.absoluteToLocal(rect)","description":"Convert a rect in global Hammerspoon coordinates to coordinates local to this screen. The result origin is relative to this screen's top-left corner.","url":"HSScreen.html#absoluteToLocal","kind":"method"},{"fullName":"HSScreen.localToAbsolute(rect)","description":"Convert a rect in local screen coordinates to global Hammerspoon coordinates.","url":"HSScreen.html#localToAbsolute","kind":"method"},{"fullName":"HSSound","description":"An object representing an audio sound that can be played, paused, and stopped. Create instances using hs.sound.fromFile() or hs.sound.named().","url":"HSSound.html","kind":"type"},{"fullName":"HSSound.identifier","description":"A unique identifier for this sound object.","url":"HSSound.html#identifier","kind":"property"},{"fullName":"HSSound.name","description":"The name of this sound. System sounds loaded by name return their name; file-based sounds return null.","url":"HSSound.html#name","kind":"property"},{"fullName":"HSSound.duration","description":"The total duration of the sound in seconds.","url":"HSSound.html#duration","kind":"property"},{"fullName":"HSSound.currentTime","description":"The current playback position in seconds. Assign a value to seek to that position.","url":"HSSound.html#currentTime","kind":"property"},{"fullName":"HSSound.volume","description":"The playback volume, from 0.0 (silent) to 1.0 (full volume).","url":"HSSound.html#volume","kind":"property"},{"fullName":"HSSound.loops","description":"Whether the sound loops when it reaches the end. Defaults to false.","url":"HSSound.html#loops","kind":"property"},{"fullName":"HSSound.isPlaying","description":"Whether the sound is currently playing.","url":"HSSound.html#isPlaying","kind":"property"},{"fullName":"HSSound.play()","description":"Starts playback from the current position.","url":"HSSound.html#play","kind":"method"},{"fullName":"HSSound.pause()","description":"Pauses playback, preserving the current position.","url":"HSSound.html#pause","kind":"method"},{"fullName":"HSSound.resume()","description":"Resumes playback from a paused position.","url":"HSSound.html#resume","kind":"method"},{"fullName":"HSSound.stop()","description":"Stops playback. The playback position is not reset.","url":"HSSound.html#stop","kind":"method"},{"fullName":"HSSound.setCallback(callback)","description":"Sets a function to be called when playback finishes. The callback receives two arguments: the sound object and a boolean — true if the sound completed naturally, false if it was stopped before finishing.","url":"HSSound.html#setCallback","kind":"method"},{"fullName":"HSSound.removeCallback()","description":"Removes the completion callback previously set with setCallback().","url":"HSSound.html#removeCallback","kind":"method"},{"fullName":"HSSound.destroy()","description":"Stops playback and releases all resources held by this sound. After calling destroy() the sound object should not be used.","url":"HSSound.html#destroy","kind":"method"},{"fullName":"HSSpotlightGroup","description":"A grouped set of Spotlight results that share a common metadata attribute value. Groups are returned by HSSpotlightQuery.groups() when grouping attributes have been configured with setGroupingAttributes(). Do not instantiate HSSpotlightGroup directly. When multiple grouping attributes are specified, groups nest: each group has subgroups() containing the next level of grouping.","url":"HSSpotlightGroup.html","kind":"type"},{"fullName":"HSSpotlightGroup.identifier","description":"A unique identifier for this group object (UUID string).","url":"HSSpotlightGroup.html#identifier","kind":"property"},{"fullName":"HSSpotlightGroup.attribute","description":"The metadata attribute name by which results in this group are clustered.","url":"HSSpotlightGroup.html#attribute","kind":"property"},{"fullName":"HSSpotlightGroup.count","description":"The number of results contained in this group.","url":"HSSpotlightGroup.html#count","kind":"property"},{"fullName":"HSSpotlightGroup.value()","description":"The shared value of the grouping attribute for all results in this group. Returns null only in the unlikely case that the underlying value cannot be bridged.","url":"HSSpotlightGroup.html#value","kind":"method"},{"fullName":"HSSpotlightGroup.results()","description":"Returns the items contained in this group as an array of HSSpotlightItem objects.","url":"HSSpotlightGroup.html#results","kind":"method"},{"fullName":"HSSpotlightGroup.subgroups()","description":"Returns nested subgroups when multiple grouping attributes were specified. Returns an empty array if no subgroups exist for this group.","url":"HSSpotlightGroup.html#subgroups","kind":"method"},{"fullName":"HSSpotlightItem","description":"An individual result returned by a Spotlight query. Instances are returned by HSSpotlightQuery.results() and related methods. Do not instantiate HSSpotlightItem directly. Metadata values are read via valueForAttribute() using standard kMDItem* keys. Call attributes() to discover which keys are populated on a particular item. Common attribute key shortcuts live in hs.spotlight.attribute.","url":"HSSpotlightItem.html","kind":"type"},{"fullName":"HSSpotlightItem.identifier","description":"A unique identifier for this result object (UUID string).","url":"HSSpotlightItem.html#identifier","kind":"property"},{"fullName":"HSSpotlightItem.attributes()","description":"Returns the list of metadata attribute names present on this item. The list is typically not exhaustive — some attributes (such as kMDItemPath) may be readable via valueForAttribute() even when absent from this list.","url":"HSSpotlightItem.html#attributes","kind":"method"},{"fullName":"HSSpotlightItem.valueForAttribute(key)","description":"Returns the value for a specific metadata attribute, or null if absent. The return type depends on the attribute: common types include strings, numbers, dates, and arrays of strings. NSURL-typed values are automatically converted to their string representation.","url":"HSSpotlightItem.html#valueForAttribute","kind":"method"},{"fullName":"HSSpotlightQuery","description":"A configurable Spotlight search query that can be started, stopped, and queried for results. Create instances via hs.spotlight.create() or the convenience helper hs.spotlight.search(). Configure the query with chainable setter methods, register a callback, then call start(). Results accumulate during the initial gathering phase (\"didStart\" → \"inProgress\" → \"didFinish\") and continue to update during the live-monitoring phase (\"didUpdate\"). Stop explicitly with stop() when you no longer need live updates.","url":"HSSpotlightQuery.html","kind":"type"},{"fullName":"HSSpotlightQuery.identifier","description":"A unique identifier for this query object (UUID string).","url":"HSSpotlightQuery.html#identifier","kind":"property"},{"fullName":"HSSpotlightQuery.count","description":"The number of results gathered so far.","url":"HSSpotlightQuery.html#count","kind":"property"},{"fullName":"HSSpotlightQuery.isRunning","description":"Whether the query is currently running (gathering or monitoring for live updates).","url":"HSSpotlightQuery.html#isRunning","kind":"property"},{"fullName":"HSSpotlightQuery.isGathering","description":"Whether the query is in the initial gathering phase. true from \"didStart\" until \"didFinish\"; false thereafter while live-monitoring.","url":"HSSpotlightQuery.html#isGathering","kind":"property"},{"fullName":"HSSpotlightQuery.setQuery(predicate)","description":"Sets the NSPredicate query string for this search. The string must be a valid NSPredicate format expression using kMDItem* attribute keys and MDQuery operators (==, !=, <, >, BEGINSWITH, CONTAINS, etc.). If the query is already running when this is called, it is stopped and restarted automatically.","url":"HSSpotlightQuery.html#setQuery","kind":"method"},{"fullName":"HSSpotlightQuery.setScopes(scopes)","description":"Sets the search scopes that restrict where Spotlight looks. Pass an array of predefined scope strings from hs.spotlight.scope, absolute directory paths, or a mix of both. Paths beginning with ~ are expanded to the user's home directory. When not set, the query defaults to hs.spotlight.scope.computer.","url":"HSSpotlightQuery.html#setScopes","kind":"method"},{"fullName":"HSSpotlightQuery.setSortDescriptors(descriptors)","description":"Sets sort descriptors that control the order of results.","url":"HSSpotlightQuery.html#setSortDescriptors","kind":"method"},{"fullName":"HSSpotlightQuery.setGroupingAttributes(attrs)","description":"Sets the attributes by which results will be grouped. When grouping attributes are set, use groups() to retrieve results organised into HSSpotlightGroup objects. Specifying multiple attributes creates nested subgroups accessible via group.subgroups().","url":"HSSpotlightQuery.html#setGroupingAttributes","kind":"method"},{"fullName":"HSSpotlightQuery.setValueListAttributes(attrs)","description":"Sets the attributes for which aggregate value-list summaries are computed. After the query finishes, valueLists() returns aggregate data for each specified attribute: distinct values and the number of results carrying each value.","url":"HSSpotlightQuery.html#setValueListAttributes","kind":"method"},{"fullName":"HSSpotlightQuery.setCallback(fn)","description":"Registers a callback that receives query lifecycle events. of HSSpotlightItem objects describing what changed in this update cycle","url":"HSSpotlightQuery.html#setCallback","kind":"method"},{"fullName":"HSSpotlightQuery.start()","description":"Starts the query. The query must have a predicate set (via setQuery()) before calling start(). Calling start() on an already-running query is a no-op.","url":"HSSpotlightQuery.html#start","kind":"method"},{"fullName":"HSSpotlightQuery.stop()","description":"Stops the query while preserving accumulated results. After stopping, results(), count, groups(), and valueLists() continue to return the last gathered data. Call start() again to resume.","url":"HSSpotlightQuery.html#stop","kind":"method"},{"fullName":"HSSpotlightQuery.results()","description":"Returns the current results as an array of HSSpotlightItem objects. The result set is briefly frozen during access to ensure consistency. Safe to call from within a query callback.","url":"HSSpotlightQuery.html#results","kind":"method"},{"fullName":"HSSpotlightQuery.groups()","description":"Returns grouped results when grouping attributes have been configured. Returns an empty array if setGroupingAttributes() was not called.","url":"HSSpotlightQuery.html#groups","kind":"method"},{"fullName":"HSSpotlightQuery.valueLists()","description":"Returns aggregate value-list summaries for attributes set via setValueListAttributes(). Returns an empty array if setValueListAttributes() was not called.","url":"HSSpotlightQuery.html#valueLists","kind":"method"},{"fullName":"HSTask","description":"Object representing an external process task","url":"HSTask.html","kind":"type"},{"fullName":"HSTask.isRunning","description":"Check if the task is currently running","url":"HSTask.html#isRunning","kind":"property"},{"fullName":"HSTask.pid","description":"The process ID of the running task","url":"HSTask.html#pid","kind":"property"},{"fullName":"HSTask.environment","description":"The environment variables for the task","url":"HSTask.html#environment","kind":"property"},{"fullName":"HSTask.workingDirectory","description":"The working directory for the task","url":"HSTask.html#workingDirectory","kind":"property"},{"fullName":"HSTask.terminationStatus","description":"The termination status of the task","url":"HSTask.html#terminationStatus","kind":"property"},{"fullName":"HSTask.terminationReason","description":"The termination reason","url":"HSTask.html#terminationReason","kind":"property"},{"fullName":"HSTask.start()","description":"Start the task","url":"HSTask.html#start","kind":"method"},{"fullName":"HSTask.terminate()","description":"Terminate the task (send SIGTERM)","url":"HSTask.html#terminate","kind":"method"},{"fullName":"HSTask.kill9()","description":"Terminate the task with extreme prejudice (send SIGKILL)","url":"HSTask.html#kill9","kind":"method"},{"fullName":"HSTask.interrupt()","description":"Interrupt the task (send SIGINT)","url":"HSTask.html#interrupt","kind":"method"},{"fullName":"HSTask.pause()","description":"Pause the task (send SIGSTOP)","url":"HSTask.html#pause","kind":"method"},{"fullName":"HSTask.resume()","description":"Resume the task (send SIGCONT)","url":"HSTask.html#resume","kind":"method"},{"fullName":"HSTask.waitUntilExit()","description":"Wait for the task to complete (blocking)","url":"HSTask.html#waitUntilExit","kind":"method"},{"fullName":"HSTask.sendInput(data)","description":"Write data to the task's stdin","url":"HSTask.html#sendInput","kind":"method"},{"fullName":"HSTask.closeInput()","description":"Close the task's stdin","url":"HSTask.html#closeInput","kind":"method"},{"fullName":"HSTimer","description":"Object representing a timer. You should not instantiate these yourself, but rather, use the methods in hs.timer to create them for you.","url":"HSTimer.html","kind":"type"},{"fullName":"HSTimer.interval","description":"The timer's interval in seconds","url":"HSTimer.html#interval","kind":"property"},{"fullName":"HSTimer.repeats","description":"Whether the timer repeats","url":"HSTimer.html#repeats","kind":"property"},{"fullName":"HSTimer.start()","description":"Start the timer","url":"HSTimer.html#start","kind":"method"},{"fullName":"HSTimer.stop()","description":"Stop the timer","url":"HSTimer.html#stop","kind":"method"},{"fullName":"HSTimer.fire()","description":"Immediately fire the timer's callback","url":"HSTimer.html#fire","kind":"method"},{"fullName":"HSTimer.running()","description":"Check if the timer is currently running","url":"HSTimer.html#running","kind":"method"},{"fullName":"HSTimer.nextTrigger()","description":"Get the number of seconds until the timer next fires","url":"HSTimer.html#nextTrigger","kind":"method"},{"fullName":"HSTimer.setNextTrigger(seconds)","description":"Set when the timer should next fire","url":"HSTimer.html#setNextTrigger","kind":"method"},{"fullName":"HSTranslationSession","description":"JavaScript-visible API for a translation session bound to a specific language pair.","url":"HSTranslationSession.html","kind":"type"},{"fullName":"HSTranslationSession.typeName","description":"The Swift type name, for JavaScript introspection.","url":"HSTranslationSession.html#typeName","kind":"property"},{"fullName":"HSTranslationSession.sourceLanguage","description":"BCP-47 identifier of the source language (e.g. \"en\").","url":"HSTranslationSession.html#sourceLanguage","kind":"property"},{"fullName":"HSTranslationSession.targetLanguage","description":"BCP-47 identifier of the target language (e.g. \"fr\").","url":"HSTranslationSession.html#targetLanguage","kind":"property"},{"fullName":"HSTranslationSession.translate(text)","description":"Translate a string from the session's source language to its target language.","url":"HSTranslationSession.html#translate","kind":"method"},{"fullName":"HSUIWindow","description":"# HSUIWindow A custom window with declarative UI building HSUIWindow allows you to create custom windows with a SwiftUI-like declarative syntax. Build interfaces using shapes, text, images, and layout containers. ## Building UI Elements ## Modifying Elements ## Examples Simple window with text and shapes: ``javascript hs.ui.window({x: 100, y: 100, w: 300, h: 200}) .vstack() .spacing(10) .padding(20) .text(\"Dashboard\") .font(HSFont.largeTitle()) .foregroundColor(\"#FFFFFF\") .rectangle() .fill(\"#4A90E2\") .cornerRadius(10) .frame({w: \"90%\", h: 80}) .end() .backgroundColor(\"#2C3E50\") .show(); ` Window with image: `javascript const img = HSImage.fromPath(\"~/Pictures/photo.jpg\") hs.ui.window({x: 100, y: 100, w: 400, h: 300}) .vstack() .padding(20) .image(img) .resizable() .aspectRatio(\"fit\") .frame({w: 360, h: 240}) .end() .show(); ``","url":"HSUIWindow.html","kind":"type"},{"fullName":"HSUIWindow.show()","description":"Show the window","url":"HSUIWindow.html#show","kind":"method"},{"fullName":"HSUIWindow.hide()","description":"Hide the window (keeps it in memory)","url":"HSUIWindow.html#hide","kind":"method"},{"fullName":"HSUIWindow.close()","description":"Close and destroy the window","url":"HSUIWindow.html#close","kind":"method"},{"fullName":"HSUIWindow.titled(show)","description":"Show or hide the window's title bar By default windows have a title bar. Pass false to create a borderless window. .closable(), .miniaturizable(), and .allowResize() only take visual effect when the window is titled.","url":"HSUIWindow.html#titled","kind":"method"},{"fullName":"HSUIWindow.closable(show)","description":"Show or hide the close button on the window Requires .titled(true) to be visible. Enabled by default.","url":"HSUIWindow.html#closable","kind":"method"},{"fullName":"HSUIWindow.miniaturizable(show)","description":"Show or hide the miniaturize (yellow) button on the window Requires .titled(true) to be visible. Enabled by default.","url":"HSUIWindow.html#miniaturizable","kind":"method"},{"fullName":"HSUIWindow.allowResize(enable)","description":"Allow or prevent the user from resizing the window Enabled by default. Only has a visual effect when .titled(true) is also set.","url":"HSUIWindow.html#allowResize","kind":"method"},{"fullName":"HSUIWindow.windowTitle(text)","description":"Set the text shown in the window's title bar Only visible when .titled(true) is set (the default).","url":"HSUIWindow.html#windowTitle","kind":"method"},{"fullName":"HSUIWindow.level(name)","description":"Set the window stacking level Controls where this window sits in the macOS window hierarchy.","url":"HSUIWindow.html#level","kind":"method"},{"fullName":"HSUIWindow.backgroundColor(colorValue)","description":"Set the window's background color","url":"HSUIWindow.html#backgroundColor","kind":"method"},{"fullName":"HSUIWindow.rectangle()","description":"Add a rectangle shape","url":"HSUIWindow.html#rectangle","kind":"method"},{"fullName":"HSUIWindow.circle()","description":"Add a circle shape","url":"HSUIWindow.html#circle","kind":"method"},{"fullName":"HSUIWindow.text(content)","description":"Add a text element or an HSString object (from hs.ui.string()) for reactive text","url":"HSUIWindow.html#text","kind":"method"},{"fullName":"HSUIWindow.image(imageValue)","description":"Add an image element","url":"HSUIWindow.html#image","kind":"method"},{"fullName":"HSUIWindow.button(label)","description":"Add a button element or an HSString object (from hs.ui.string()) for reactive text","url":"HSUIWindow.html#button","kind":"method"},{"fullName":"HSUIWindow.vstack()","description":"Begin a vertical stack (elements arranged top to bottom)","url":"HSUIWindow.html#vstack","kind":"method"},{"fullName":"HSUIWindow.hstack()","description":"Begin a horizontal stack (elements arranged left to right)","url":"HSUIWindow.html#hstack","kind":"method"},{"fullName":"HSUIWindow.zstack()","description":"Begin a z-stack (overlapping elements)","url":"HSUIWindow.html#zstack","kind":"method"},{"fullName":"HSUIWindow.spacer()","description":"Add flexible spacing that expands to fill available space","url":"HSUIWindow.html#spacer","kind":"method"},{"fullName":"HSUIWindow.webview(element)","description":"Embed a web browser element created with hs.ui.webview() (macOS 26+) The element fills the available space in the window layout. Keep a reference to the element to call navigation methods after the window is shown.","url":"HSUIWindow.html#webview","kind":"method"},{"fullName":"HSUIWindow.end()","description":"End the current layout container","url":"HSUIWindow.html#end","kind":"method"},{"fullName":"HSUIWindow.fill(colorValue)","description":"Fill a shape with a color","url":"HSUIWindow.html#fill","kind":"method"},{"fullName":"HSUIWindow.stroke(colorValue)","description":"Add a stroke (border) to a shape","url":"HSUIWindow.html#stroke","kind":"method"},{"fullName":"HSUIWindow.strokeWidth(width)","description":"Set the stroke width","url":"HSUIWindow.html#strokeWidth","kind":"method"},{"fullName":"HSUIWindow.cornerRadius(radius)","description":"Round the corners of a shape","url":"HSUIWindow.html#cornerRadius","kind":"method"},{"fullName":"HSUIWindow.frame(dict)","description":"Set the frame (size) of an element","url":"HSUIWindow.html#frame","kind":"method"},{"fullName":"HSUIWindow.opacity(value)","description":"Set the opacity of an element","url":"HSUIWindow.html#opacity","kind":"method"},{"fullName":"HSUIWindow.font(font)","description":"Set the font for a text element","url":"HSUIWindow.html#font","kind":"method"},{"fullName":"HSUIWindow.foregroundColor(colorValue)","description":"Set the text color","url":"HSUIWindow.html#foregroundColor","kind":"method"},{"fullName":"HSUIWindow.resizable()","description":"Make an image resizable (allows it to scale with frame size)","url":"HSUIWindow.html#resizable","kind":"method"},{"fullName":"HSUIWindow.aspectRatio(mode)","description":"Set the aspect ratio mode for an image","url":"HSUIWindow.html#aspectRatio","kind":"method"},{"fullName":"HSUIWindow.padding(value)","description":"Add padding around a layout container","url":"HSUIWindow.html#padding","kind":"method"},{"fullName":"HSUIWindow.spacing(value)","description":"Set spacing between elements in a stack","url":"HSUIWindow.html#spacing","kind":"method"},{"fullName":"HSUIWindow.onClick(callback)","description":"Set a callback to fire when the element is clicked","url":"HSUIWindow.html#onClick","kind":"method"},{"fullName":"HSUIWindow.onHover(callback)","description":"Set a callback to fire when the cursor enters or leaves the element","url":"HSUIWindow.html#onHover","kind":"method"},{"fullName":"HSUIAlert","description":"# HSUIAlert A temporary on-screen notification Displays a message that automatically fades out after a specified duration. Positioned in the center of the screen with a semi-transparent background. ## Example ``javascript hs.ui.alert(\"Task completed!\") .font(HSFont.headline()) .duration(5) .padding(30) .show(); ``","url":"HSUIAlert.html","kind":"type"},{"fullName":"HSUIAlert.font(font)","description":"Set the font for the alert text","url":"HSUIAlert.html#font","kind":"method"},{"fullName":"HSUIAlert.duration(seconds)","description":"Set how long the alert is displayed","url":"HSUIAlert.html#duration","kind":"method"},{"fullName":"HSUIAlert.padding(points)","description":"Set the padding around the alert text","url":"HSUIAlert.html#padding","kind":"method"},{"fullName":"HSUIAlert.position(dict)","description":"Set a custom position for the alert","url":"HSUIAlert.html#position","kind":"method"},{"fullName":"HSUIAlert.show()","description":"Show the alert","url":"HSUIAlert.html#show","kind":"method"},{"fullName":"HSUIAlert.close()","description":"Close the alert immediately","url":"HSUIAlert.html#close","kind":"method"},{"fullName":"HSUIDialog","description":"# HSUIDialog A modal dialog with customizable buttons Shows a blocking dialog with a message, optional informative text, and custom buttons. Use the callback to respond to button presses. ## Example ``javascript hs.ui.dialog(\"Save changes?\") .informativeText(\"Your document has unsaved changes.\") .buttons([\"Save\", \"Don't Save\", \"Cancel\"]) .onButton((index) => { if (index === 0) { console.log(\"Saving...\"); } else if (index === 1) { console.log(\"Discarding changes...\"); } }) .show(); ``","url":"HSUIDialog.html","kind":"type"},{"fullName":"HSUIDialog.informativeText(text)","description":"Set additional informative text below the main message","url":"HSUIDialog.html#informativeText","kind":"method"},{"fullName":"HSUIDialog.buttons(labels)","description":"Set custom button labels","url":"HSUIDialog.html#buttons","kind":"method"},{"fullName":"HSUIDialog.style(style)","description":"Set the dialog style","url":"HSUIDialog.html#style","kind":"method"},{"fullName":"HSUIDialog.onButton(callback)","description":"Set the callback for button presses","url":"HSUIDialog.html#onButton","kind":"method"},{"fullName":"HSUIDialog.show()","description":"Show the dialog","url":"HSUIDialog.html#show","kind":"method"},{"fullName":"HSUIDialog.close()","description":"Close the dialog programmatically","url":"HSUIDialog.html#close","kind":"method"},{"fullName":"HSUIFilePicker","description":"# HSUIFilePicker A file or directory selection dialog Shows a standard macOS open panel for selecting files or directories. Supports multiple selection, file type filtering, and more. ## Examples ### File Picker ``javascript hs.ui.filePicker() .message(\"Choose a file to open\") .allowedFileTypes([\"txt\", \"md\", \"js\"]) .onSelection((path) => { if (path) { console.log(\"Selected: \" + path); } else { console.log(\"User cancelled\"); } }) .show(); ` ### Directory Picker with Multiple Selection `javascript hs.ui.filePicker() .message(\"Choose directories to backup\") .canChooseFiles(false) .canChooseDirectories(true) .allowsMultipleSelection(true) .onSelection((paths) => { if (paths) { paths.forEach(p => console.log(\"Dir: \" + p)); } }) .show(); ``","url":"HSUIFilePicker.html","kind":"type"},{"fullName":"HSUIFilePicker.message(text)","description":"Set the message displayed in the picker","url":"HSUIFilePicker.html#message","kind":"method"},{"fullName":"HSUIFilePicker.defaultPath(path)","description":"Set the starting directory","url":"HSUIFilePicker.html#defaultPath","kind":"method"},{"fullName":"HSUIFilePicker.canChooseFiles(value)","description":"Set whether files can be selected","url":"HSUIFilePicker.html#canChooseFiles","kind":"method"},{"fullName":"HSUIFilePicker.canChooseDirectories(value)","description":"Set whether directories can be selected","url":"HSUIFilePicker.html#canChooseDirectories","kind":"method"},{"fullName":"HSUIFilePicker.allowsMultipleSelection(value)","description":"Set whether multiple items can be selected","url":"HSUIFilePicker.html#allowsMultipleSelection","kind":"method"},{"fullName":"HSUIFilePicker.allowedFileTypes(types)","description":"Restrict to specific file types","url":"HSUIFilePicker.html#allowedFileTypes","kind":"method"},{"fullName":"HSUIFilePicker.resolvesAliases(value)","description":"Set whether to resolve symbolic links","url":"HSUIFilePicker.html#resolvesAliases","kind":"method"},{"fullName":"HSUIFilePicker.onSelection(callback)","description":"Set the callback for file selection","url":"HSUIFilePicker.html#onSelection","kind":"method"},{"fullName":"HSUIFilePicker.show()","description":"Show the file picker dialog","url":"HSUIFilePicker.html#show","kind":"method"},{"fullName":"HSUITextPrompt","description":"# HSUITextPrompt A modal dialog with text input Shows a blocking dialog with a text input field. The callback receives both the button index and the entered text. ## Example ``javascript hs.ui.textPrompt(\"Enter your name\") .informativeText(\"Please provide your full name\") .defaultText(\"John Doe\") .buttons([\"OK\", \"Cancel\"]) .onButton((buttonIndex, text) => { if (buttonIndex === 0) { console.log(\"User entered: \" + text); } }) .show(); ``","url":"HSUITextPrompt.html","kind":"type"},{"fullName":"HSUITextPrompt.informativeText(text)","description":"Set additional informative text below the main message","url":"HSUITextPrompt.html#informativeText","kind":"method"},{"fullName":"HSUITextPrompt.defaultText(text)","description":"Set the default text in the input field","url":"HSUITextPrompt.html#defaultText","kind":"method"},{"fullName":"HSUITextPrompt.buttons(labels)","description":"Set custom button labels","url":"HSUITextPrompt.html#buttons","kind":"method"},{"fullName":"HSUITextPrompt.onButton(callback)","description":"Set the callback for button presses","url":"HSUITextPrompt.html#onButton","kind":"method"},{"fullName":"HSUITextPrompt.show()","description":"Show the prompt dialog","url":"HSUITextPrompt.html#show","kind":"method"},{"fullName":"UIWebView","description":"# hs.ui.webview A web browser element for embedding in hs.ui.window layouts Available on macOS 26.0 or later, hs.ui.webview() creates a web browser element backed by a SwiftUI WebView and WebPage. Embed it in any hs.ui.window using .webview(element) — it fills the available space and can sit alongside other elements in stacks. ``javascript const wv = hs.ui.webview() .toolbar([\"back\", \"forward\", \"reload\", \"url\"]) .loadURL(\"https://apple.com\")","url":"UIWebView.html","kind":"type"},{"fullName":"UIWebView.url","description":"The URL of the current page, or null if no page is loaded","url":"UIWebView.html#url","kind":"property"},{"fullName":"UIWebView.title","description":"The title of the current page","url":"UIWebView.html#title","kind":"property"},{"fullName":"UIWebView.isLoading","description":"Whether the web view is currently loading a page","url":"UIWebView.html#isLoading","kind":"property"},{"fullName":"UIWebView.estimatedProgress","description":"The estimated loading progress from 0.0 to 1.0","url":"UIWebView.html#estimatedProgress","kind":"property"},{"fullName":"UIWebView.canGoBack","description":"Whether the web view can navigate back in history","url":"UIWebView.html#canGoBack","kind":"property"},{"fullName":"UIWebView.canGoForward","description":"Whether the web view can navigate forward in history","url":"UIWebView.html#canGoForward","kind":"property"},{"fullName":"UIWebView.loadURL(urlString)","description":"Load a URL in the web view","url":"UIWebView.html#loadURL","kind":"method"},{"fullName":"UIWebView.loadHTML(html)","description":"Load an HTML string directly into the web view","url":"UIWebView.html#loadHTML","kind":"method"},{"fullName":"UIWebView.goBack()","description":"Navigate back in the browser history","url":"UIWebView.html#goBack","kind":"method"},{"fullName":"UIWebView.goForward()","description":"Navigate forward in the browser history","url":"UIWebView.html#goForward","kind":"method"},{"fullName":"UIWebView.reload()","description":"Reload the current page","url":"UIWebView.html#reload","kind":"method"},{"fullName":"UIWebView.stopLoading()","description":"Stop loading the current page","url":"UIWebView.html#stopLoading","kind":"method"},{"fullName":"UIWebView.userAgent(ua)","description":"Set a custom User-Agent string for HTTP requests","url":"UIWebView.html#userAgent","kind":"method"},{"fullName":"UIWebView.inspectable(value)","description":"Enable or disable the Safari Web Inspector for this web view When enabled, the web view appears in Safari → Develop menu.","url":"UIWebView.html#inspectable","kind":"method"},{"fullName":"UIWebView.toolbar(items)","description":"Configure the toolbar with a list of standard and custom items The toolbar renders above the web view. Each element of the array is either a string naming a standard control or a dictionary describing a custom button. An empty array (or omitting this call) hides the toolbar. Standard string items: \"back\", \"forward\", \"reload\", \"url\", \"spacer\".","url":"UIWebView.html#toolbar","kind":"method"},{"fullName":"UIWebView.backForwardGestures(enabled)","description":"Enable or disable the macOS back/forward trackpad swipe gestures Gestures are enabled by default. Pass false to disable them.","url":"UIWebView.html#backForwardGestures","kind":"method"},{"fullName":"UIWebView.magnificationGestures(enabled)","description":"Enable or disable the trackpad pinch-to-zoom magnification gesture The gesture is enabled by default. Pass false to disable it.","url":"UIWebView.html#magnificationGestures","kind":"method"},{"fullName":"UIWebView.linkPreviews(enabled)","description":"Enable or disable link preview popovers shown on force-click Link previews are enabled by default. Pass false to disable them.","url":"UIWebView.html#linkPreviews","kind":"method"},{"fullName":"UIWebView.contentBackground(visible)","description":"Control whether the web page background is visible Pass false to make the web view background transparent. Enabled (visible) by default.","url":"UIWebView.html#contentBackground","kind":"method"},{"fullName":"UIWebView.onLoadChange(callback)","description":"Register a callback that fires when loading state or progress changes Called whenever isLoading, url, title, or estimatedProgress changes.","url":"UIWebView.html#onLoadChange","kind":"method"},{"fullName":"UIWebView.onNavigate(callback)","description":"Register a callback that fires when navigation to a new page completes","url":"UIWebView.html#onNavigate","kind":"method"},{"fullName":"UIWebView.onTitleChange(callback)","description":"Register a callback that fires when the page title changes","url":"UIWebView.html#onTitleChange","kind":"method"},{"fullName":"UIWebView.onNavigationDecision(callback)","description":"Register a callback that controls whether navigation is allowed Called before each navigation. Return true to allow or false to block.","url":"UIWebView.html#onNavigationDecision","kind":"method"},{"fullName":"UIWebView.execJS(script)","description":"Execute JavaScript in the web page without capturing the result","url":"UIWebView.html#execJS","kind":"method"},{"fullName":"UIWebView.evalJSResult(script, callback)","description":"Execute JavaScript in the web page and deliver the result to a callback The JavaScript method name is evalJSResult — it derives from the internal Objective-C selector evalJS:result:.","url":"UIWebView.html#evalJSResult","kind":"method"},{"fullName":"HSWindow","description":"Object representing a window. You should not instantiate these directly, but rather, use the methods in hs.window to create them for you. Note that this type uses private macOS APIs","url":"HSWindow.html","kind":"type"},{"fullName":"HSWindow.title","description":"The window's title","url":"HSWindow.html#title","kind":"property"},{"fullName":"HSWindow.application","description":"The application that owns this window","url":"HSWindow.html#application","kind":"property"},{"fullName":"HSWindow.pid","description":"The process ID of the application that owns this window","url":"HSWindow.html#pid","kind":"property"},{"fullName":"HSWindow.id","description":"The window's underlying ID. A value of 0 or -1 likely means no window ID could be determined.","url":"HSWindow.html#id","kind":"property"},{"fullName":"HSWindow.isMinimized","description":"Whether the window is minimized","url":"HSWindow.html#isMinimized","kind":"property"},{"fullName":"HSWindow.isVisible","description":"Whether the window is visible (not minimized or hidden)","url":"HSWindow.html#isVisible","kind":"property"},{"fullName":"HSWindow.isFocused","description":"Whether the window is focused","url":"HSWindow.html#isFocused","kind":"property"},{"fullName":"HSWindow.isFullscreen","description":"Whether the window is fullscreen","url":"HSWindow.html#isFullscreen","kind":"property"},{"fullName":"HSWindow.isStandard","description":"Whether the window is standard (has a titlebar)","url":"HSWindow.html#isStandard","kind":"property"},{"fullName":"HSWindow.position","description":"The window's position on screen {x: Int, y: Int}","url":"HSWindow.html#position","kind":"property"},{"fullName":"HSWindow.size","description":"The window's size {w: Int, h: Int}","url":"HSWindow.html#size","kind":"property"},{"fullName":"HSWindow.frame","description":"The window's frame {x: Int, y: Int, w: Int, h: Int}","url":"HSWindow.html#frame","kind":"property"},{"fullName":"HSWindow.screen","description":"The screen that contains the largest portion of this window.","url":"HSWindow.html#screen","kind":"property"},{"fullName":"HSWindow.focus()","description":"Focus this window","url":"HSWindow.html#focus","kind":"method"},{"fullName":"HSWindow.minimize()","description":"Minimize this window","url":"HSWindow.html#minimize","kind":"method"},{"fullName":"HSWindow.unminimize()","description":"Unminimize this window","url":"HSWindow.html#unminimize","kind":"method"},{"fullName":"HSWindow.raise()","description":"Raise this window to the front","url":"HSWindow.html#raise","kind":"method"},{"fullName":"HSWindow.toggleFullscreen()","description":"Toggle fullscreen mode","url":"HSWindow.html#toggleFullscreen","kind":"method"},{"fullName":"HSWindow.close()","description":"Close this window","url":"HSWindow.html#close","kind":"method"},{"fullName":"HSWindow.centerOnScreen()","description":"Center the window on the screen","url":"HSWindow.html#centerOnScreen","kind":"method"},{"fullName":"HSWindow.axElement()","description":"Get the underlying AXElement","url":"HSWindow.html#axElement","kind":"method"},{"fullName":"HSColor","description":"Bridge type for working with colors in JavaScript","url":"HSColor.html","kind":"type"},{"fullName":"HSColor.rgb(r, g, b, a)","description":"Create a color from RGB values","url":"HSColor.html#rgb","kind":"method"},{"fullName":"HSColor.hex(hex)","description":"Create a color from a hex string","url":"HSColor.html#hex","kind":"method"},{"fullName":"HSColor.named(name)","description":"Create a color from a named system color","url":"HSColor.html#named","kind":"method"},{"fullName":"HSColor.set(value)","description":"Update this color's value. If this color is bound to a UI element, the canvas re-renders automatically.","url":"HSColor.html#set","kind":"method"},{"fullName":"HSFont","description":"This is a JavaScript object used to represent macOS fonts. It includes a variety of static methods that can instantiate the various font sizes commonly used with UI elements, and also includes static methods for instantiating the system font at various sizes/weights, or any custom font available on the system.","url":"HSFont.html","kind":"type"},{"fullName":"HSFont.body()","description":"Body text style","url":"HSFont.html#body","kind":"method"},{"fullName":"HSFont.callout()","description":"Callout text style","url":"HSFont.html#callout","kind":"method"},{"fullName":"HSFont.caption()","description":"Caption text style","url":"HSFont.html#caption","kind":"method"},{"fullName":"HSFont.caption2()","description":"Caption2 text style","url":"HSFont.html#caption2","kind":"method"},{"fullName":"HSFont.footnote()","description":"Footnote text style","url":"HSFont.html#footnote","kind":"method"},{"fullName":"HSFont.headline()","description":"Headline text style","url":"HSFont.html#headline","kind":"method"},{"fullName":"HSFont.largeTitle()","description":"Large Title text style","url":"HSFont.html#largeTitle","kind":"method"},{"fullName":"HSFont.subheadline()","description":"Sub-headline text style","url":"HSFont.html#subheadline","kind":"method"},{"fullName":"HSFont.title()","description":"Title text style","url":"HSFont.html#title","kind":"method"},{"fullName":"HSFont.title2()","description":"Title2 text style","url":"HSFont.html#title2","kind":"method"},{"fullName":"HSFont.title3()","description":"Title3 text style","url":"HSFont.html#title3","kind":"method"},{"fullName":"HSFont.system(size)","description":"The system font in a custom size","url":"HSFont.html#system","kind":"method"},{"fullName":"HSFont.system(size, weight)","description":"The system font in a custom size with a choice of weights","url":"HSFont.html#system","kind":"method"},{"fullName":"HSFont.custom(name, size)","description":"A font present on the system at a given size","url":"HSFont.html#custom","kind":"method"},{"fullName":"HSImage","description":"Bridge type for working with images in JavaScript HSImage provides a comprehensive API for loading, manipulating, and saving images. It supports various image sources including files, system icons, app bundles, and URLs. ## Loading Images ``javascript // Load from file const img = HSImage.fromPath(\"/path/to/image.png\")","url":"HSImage.html","kind":"type"},{"fullName":"HSImage.size","description":"The size of the image. Setting this resizes the image in place to the exact dimensions.","url":"HSImage.html#size","kind":"property"},{"fullName":"HSImage.name","description":"The name of the image, or null if not set.","url":"HSImage.html#name","kind":"property"},{"fullName":"HSImage.template","description":"Whether the image is a template image. Template images are tinted by the system to match the appearance context (e.g. menu bar icons).","url":"HSImage.html#template","kind":"property"},{"fullName":"HSImage.fromPath(path)","description":"Load an image from a file path","url":"HSImage.html#fromPath","kind":"method"},{"fullName":"HSImage.fromName(name)","description":"Load a system image by name","url":"HSImage.html#fromName","kind":"method"},{"fullName":"HSImage.fromSymbol(name)","description":"Load a system symbol by name","url":"HSImage.html#fromSymbol","kind":"method"},{"fullName":"HSImage.fromAppBundle(bundleID, withFallbackSymbol)","description":"Load an app's icon by bundle identifier","url":"HSImage.html#fromAppBundle","kind":"method"},{"fullName":"HSImage.iconForFile(path)","description":"Get the icon for a file","url":"HSImage.html#iconForFile","kind":"method"},{"fullName":"HSImage.iconForFileType(fileType)","description":"Get the icon for a file type","url":"HSImage.html#iconForFileType","kind":"method"},{"fullName":"HSImage.fromURL(url)","description":"Load an image from a URL (asynchronous)","url":"HSImage.html#fromURL","kind":"method"},{"fullName":"HSImage.copyImage()","description":"Create a copy of the image","url":"HSImage.html#copyImage","kind":"method"},{"fullName":"HSImage.croppedCopy(rect)","description":"Create a cropped copy of the image","url":"HSImage.html#croppedCopy","kind":"method"},{"fullName":"HSImage.saveToFile(path)","description":"Save the image to a file","url":"HSImage.html#saveToFile","kind":"method"},{"fullName":"HSImage.set(value)","description":"Replace this image's content. If this image is bound to a UI element, the canvas re-renders automatically.","url":"HSImage.html#set","kind":"method"},{"fullName":"HSPoint","description":"This is a JavaScript object used to represent coordinates, or \"points\", as used in various places throughout Hammerspoon's API, particularly where dealing with positions on a screen. Behind the scenes it is a wrapper for the CGPoint type in Swift/ObjectiveC.","url":"HSPoint.html","kind":"type"},{"fullName":"HSPoint.x","description":"A coordinate for the x-axis position of this point","url":"HSPoint.html#x","kind":"property"},{"fullName":"HSPoint.y","description":"A coordinate for the y-axis position of this point","url":"HSPoint.html#y","kind":"property"},{"fullName":"HSRect","description":"This is a JavaScript object used to represent a rectangle, as used in various places throughout Hammerspoon's API, particularly where dealing with portions of a display. Behind the scenes it is a wrapper for the CGRect type in Swift/ObjectiveC.","url":"HSRect.html","kind":"type"},{"fullName":"HSRect.x","description":"An x-axis coordinate for the top-left point of the rectangle","url":"HSRect.html#x","kind":"property"},{"fullName":"HSRect.y","description":"A y-axis coordinate for the top-left point of the rectangle","url":"HSRect.html#y","kind":"property"},{"fullName":"HSRect.w","description":"The width of the rectangle","url":"HSRect.html#w","kind":"property"},{"fullName":"HSRect.h","description":"The height of the rectangle","url":"HSRect.html#h","kind":"property"},{"fullName":"HSRect.origin","description":"The \"origin\" of the rectangle, ie the coordinates of its top left corner, as an HSPoint object","url":"HSRect.html#origin","kind":"property"},{"fullName":"HSRect.size","description":"The size of the rectangle, ie its width and height, as an HSSize object","url":"HSRect.html#size","kind":"property"},{"fullName":"HSSize","description":"This is a JavaScript object used to represent the size of a rectangle, as used in various places throughout Hammerspoon's API, particularly where dealing with portions of a display. Behind the scenes it is a wrapper for the CGSize type in Swift/ObjectiveC.","url":"HSSize.html","kind":"type"},{"fullName":"HSSize.w","description":"The width of the rectangle","url":"HSSize.html#w","kind":"property"},{"fullName":"HSSize.h","description":"The height of the rectangle","url":"HSSize.html#h","kind":"property"},{"fullName":"HSString","description":"A reactive string container. Pass to .text() to get automatic re-renders when .set() is called from JavaScript.","url":"HSString.html","kind":"type"},{"fullName":"HSString.value","description":"The current string value","url":"HSString.html#value","kind":"property"},{"fullName":"HSString.set(newValue)","description":"Update the string value, triggering a re-render if bound to a UI element","url":"HSString.html#set","kind":"method"}]; +const searchIndex = [{"fullName":"console","description":"These functions are provided to maintain convenience with the console.log() function present in many JavaScript instances.","url":"console.html","kind":"module"},{"fullName":"console.log(message)","description":"Log a message to the Hammerspoon Log Window","url":"console.html#log","kind":"method"},{"fullName":"console.error(message)","description":"Log an error to the Hammerspoon Log Window","url":"console.html#error","kind":"method"},{"fullName":"console.warn(message)","description":"Log a warning to the Hammerspoon Log WIndow","url":"console.html#warn","kind":"method"},{"fullName":"console.info(message)","description":"Log an informational message to the Hammerspoon Log Window","url":"console.html#info","kind":"method"},{"fullName":"console.debug(message)","description":"Log a debug message to the Hammerspoon Log Window","url":"console.html#debug","kind":"method"},{"fullName":"hs","description":"","url":"hs.html","kind":"module"},{"fullName":"hs.reload()","description":"Destroy the current JavaScript runtime and start a new one, loading all configuration from disk again","url":"hs.html#reload","kind":"method"},{"fullName":"hs.collectGarbage()","description":"Force garbage collection of JavaScript objects that no longer have any references","url":"hs.html#collectGarbage","kind":"method"},{"fullName":"hs.openConsole()","description":"Open the Hammerspoon Console window","url":"hs.html#openConsole","kind":"method"},{"fullName":"hs.closeConsole()","description":"Close the Hammerspoon Console window","url":"hs.html#closeConsole","kind":"method"},{"fullName":"hs.clearConsole()","description":"Clear the Hammerspoon Console log","url":"hs.html#clearConsole","kind":"method"},{"fullName":"hs.appinfo","description":"Module for accessing information about the Hammerspoon application itself","url":"hs.appinfo.html","kind":"module"},{"fullName":"hs.appinfo.appName","description":"The application's internal name (e.g., \"Hammerspoon 2\")","url":"hs.appinfo.html#appName","kind":"property"},{"fullName":"hs.appinfo.displayName","description":"The application's display name shown to users","url":"hs.appinfo.html#displayName","kind":"property"},{"fullName":"hs.appinfo.version","description":"The application's version string (e.g., \"2.0.0\")","url":"hs.appinfo.html#version","kind":"property"},{"fullName":"hs.appinfo.build","description":"The application's build number","url":"hs.appinfo.html#build","kind":"property"},{"fullName":"hs.appinfo.minimumOSVersion","description":"The minimum macOS version required to run this application","url":"hs.appinfo.html#minimumOSVersion","kind":"property"},{"fullName":"hs.appinfo.copyrightNotice","description":"The copyright notice for this application","url":"hs.appinfo.html#copyrightNotice","kind":"property"},{"fullName":"hs.appinfo.bundleIdentifier","description":"The application's bundle identifier (e.g., \"com.hammerspoon.Hammerspoon-2\")","url":"hs.appinfo.html#bundleIdentifier","kind":"property"},{"fullName":"hs.appinfo.bundlePath","description":"The filesystem path to the application bundle","url":"hs.appinfo.html#bundlePath","kind":"property"},{"fullName":"hs.appinfo.resourcePath","description":"The filesystem path to the application's resource directory","url":"hs.appinfo.html#resourcePath","kind":"property"},{"fullName":"hs.appinfo.configPath","description":"The filesystem path to the main Hammerspoon 2 configuration file","url":"hs.appinfo.html#configPath","kind":"property"},{"fullName":"hs.appinfo.configDir","description":"The filesystem path to the directory Hammerspoon 2 loaded its config from","url":"hs.appinfo.html#configDir","kind":"property"},{"fullName":"hs.application","description":"Module for interacting with applications","url":"hs.application.html","kind":"module"},{"fullName":"hs.application.runningApplications()","description":"Fetch all running applications","url":"hs.application.html#runningApplications","kind":"method"},{"fullName":"hs.application.matchingName(name)","description":"Fetch the first running application that matches a name","url":"hs.application.html#matchingName","kind":"method"},{"fullName":"hs.application.matchingBundleID(bundleID)","description":"Fetch the first running application that matches a Bundle ID","url":"hs.application.html#matchingBundleID","kind":"method"},{"fullName":"hs.application.fromPID(pid)","description":"Fetch the running application that matches a POSIX PID","url":"hs.application.html#fromPID","kind":"method"},{"fullName":"hs.application.frontmost()","description":"Fetch the currently focused application","url":"hs.application.html#frontmost","kind":"method"},{"fullName":"hs.application.menuBarOwner()","description":"Fetch the application which currently owns the menu bar","url":"hs.application.html#menuBarOwner","kind":"method"},{"fullName":"hs.application.pathForBundleID(bundleID)","description":"Fetch the filesystem path for an application","url":"hs.application.html#pathForBundleID","kind":"method"},{"fullName":"hs.application.pathsForBundleID(bundleID)","description":"Fetch filesystem paths for an application","url":"hs.application.html#pathsForBundleID","kind":"method"},{"fullName":"hs.application.pathForFileType(fileType)","description":"Fetch filesystem path for an application able to open a given file type","url":"hs.application.html#pathForFileType","kind":"method"},{"fullName":"hs.application.pathsForFileType(fileType)","description":"Fetch filesystem paths for applications able to open a given file type","url":"hs.application.html#pathsForFileType","kind":"method"},{"fullName":"hs.application.launchOrFocus(bundleID)","description":"Launch an application, or give it focus if it's already running","url":"hs.application.html#launchOrFocus","kind":"method"},{"fullName":"hs.application.addWatcher(listener)","description":"Create a watcher for application events","url":"hs.application.html#addWatcher","kind":"method"},{"fullName":"hs.application.removeWatcher(listener)","description":"Remove a watcher for application events","url":"hs.application.html#removeWatcher","kind":"method"},{"fullName":"hs.audiodevice","description":"Module for discovering and controlling audio devices.","url":"hs.audiodevice.html","kind":"module"},{"fullName":"hs.audiodevice.all()","description":"All audio devices attached to the system.","url":"hs.audiodevice.html#all","kind":"method"},{"fullName":"hs.audiodevice.allOutputDevices()","description":"All audio devices that have at least one output stream.","url":"hs.audiodevice.html#allOutputDevices","kind":"method"},{"fullName":"hs.audiodevice.allInputDevices()","description":"All audio devices that have at least one input stream.","url":"hs.audiodevice.html#allInputDevices","kind":"method"},{"fullName":"hs.audiodevice.defaultOutputDevice()","description":"The current system default output device.","url":"hs.audiodevice.html#defaultOutputDevice","kind":"method"},{"fullName":"hs.audiodevice.defaultInputDevice()","description":"The current system default input device.","url":"hs.audiodevice.html#defaultInputDevice","kind":"method"},{"fullName":"hs.audiodevice.defaultEffectDevice()","description":"The current system alert sound device.","url":"hs.audiodevice.html#defaultEffectDevice","kind":"method"},{"fullName":"hs.audiodevice.findDeviceByName(name)","description":"Find the first audio device whose name matches the given string.","url":"hs.audiodevice.html#findDeviceByName","kind":"method"},{"fullName":"hs.audiodevice.findDeviceByUID(uid)","description":"Find the audio device with the given unique identifier.","url":"hs.audiodevice.html#findDeviceByUID","kind":"method"},{"fullName":"hs.audiodevice.addWatcher(listener)","description":"Register a listener for all system-level audio configuration events.","url":"hs.audiodevice.html#addWatcher","kind":"method"},{"fullName":"hs.audiodevice.removeWatcher(listener)","description":"Remove a previously registered system-level listener.","url":"hs.audiodevice.html#removeWatcher","kind":"method"},{"fullName":"hs.audiodevice._makeDeviceEmitter()","description":"SKIP_DOCS","url":"hs.audiodevice.html#_makeDeviceEmitter","kind":"method"},{"fullName":"hs.ax","description":"# Accessibility API Module","url":"hs.ax.html","kind":"module"},{"fullName":"hs.ax.notificationTypes","description":"A dictionary containing all of the notification types that can be used with hs.ax.addWatcher()","url":"hs.ax.html#notificationTypes","kind":"property"},{"fullName":"hs.ax.systemWideElement()","description":"Get the system-wide accessibility element","url":"hs.ax.html#systemWideElement","kind":"method"},{"fullName":"hs.ax.applicationElement(element)","description":"Get the accessibility element for an application","url":"hs.ax.html#applicationElement","kind":"method"},{"fullName":"hs.ax.windowElement(window)","description":"Get the accessibility element for a window","url":"hs.ax.html#windowElement","kind":"method"},{"fullName":"hs.ax.elementAtPoint(point)","description":"Get the accessibility element at the specific screen position","url":"hs.ax.html#elementAtPoint","kind":"method"},{"fullName":"hs.ax.addWatcher(application, notification, listener)","description":"Add a watcher for application AX events","url":"hs.ax.html#addWatcher","kind":"method"},{"fullName":"hs.ax.removeWatcher(application, notification, listener)","description":"Remove a watcher for application AX events","url":"hs.ax.html#removeWatcher","kind":"method"},{"fullName":"hs.ax.focusedElement()","description":"Fetch the focused UI element","url":"hs.ax.html#focusedElement","kind":"method"},{"fullName":"hs.ax.findByRole(role, parent)","description":"Find AX elements matching a given role","url":"hs.ax.html#findByRole","kind":"method"},{"fullName":"hs.ax.findByTitle(title, parent)","description":"Find AX elements whose title contains a given string","url":"hs.ax.html#findByTitle","kind":"method"},{"fullName":"hs.ax.printHierarchy(element, maxDepth)","description":"Print the accessibility hierarchy of an element to the Console","url":"hs.ax.html#printHierarchy","kind":"method"},{"fullName":"hs.bonjour","description":"Discover and publish Bonjour (mDNS / Zeroconf) network services.","url":"hs.bonjour.html","kind":"module"},{"fullName":"hs.bonjour.serviceTypes","description":"A frozen object mapping short service-type names to their mDNS strings. Populated by the JavaScript enhancement layer.","url":"hs.bonjour.html#serviceTypes","kind":"property"},{"fullName":"hs.bonjour.createSearch()","description":"Creates a new Bonjour search for discovering services or domains. Call one of the find… methods on the returned search to start discovering. Remove it with removeSearch() when finished.","url":"hs.bonjour.html#createSearch","kind":"method"},{"fullName":"hs.bonjour.removeSearch(search)","description":"Stops and removes a previously created search.","url":"hs.bonjour.html#removeSearch","kind":"method"},{"fullName":"hs.bonjour.advertise(name, type, port, domain, callback)","description":"Starts advertising a local service on the network. If domain is omitted or not a string, it defaults to \"local.\". If the 4th argument is a function, it is used as the callback and domain defaults to \"local.\".","url":"hs.bonjour.html#advertise","kind":"method"},{"fullName":"hs.bonjour.stopAdvertising(name, type)","description":"Stops advertising a service previously started with advertise().","url":"hs.bonjour.html#stopAdvertising","kind":"method"},{"fullName":"hs.bonjour.networkServices(timeout)","description":"Returns a Promise that resolves to an array of service-type strings currently advertised on the local network. Internally searches for _services._dns-sd._udp. services, collects results for up to timeout seconds (or until the browser signals no more results), then resolves.","url":"hs.bonjour.html#networkServices","kind":"method"},{"fullName":"hs.camera","description":"Module for discovering and interacting with camera devices.","url":"hs.camera.html","kind":"module"},{"fullName":"hs.camera.all()","description":"All video camera devices currently connected to the system.","url":"hs.camera.html#all","kind":"method"},{"fullName":"hs.camera.findByName(name)","description":"Find the first camera whose name matches the given string.","url":"hs.camera.html#findByName","kind":"method"},{"fullName":"hs.camera.findByUID(uid)","description":"Find the camera with the given unique identifier.","url":"hs.camera.html#findByUID","kind":"method"},{"fullName":"hs.camera.addWatcher(listener)","description":"Register a listener for camera device connect/disconnect events.","url":"hs.camera.html#addWatcher","kind":"method"},{"fullName":"hs.camera.removeWatcher(listener)","description":"Remove a previously registered module-level event listener.","url":"hs.camera.html#removeWatcher","kind":"method"},{"fullName":"hs.camera._makeCameraEmitter()","description":"SKIP_DOCS","url":"hs.camera.html#_makeCameraEmitter","kind":"method"},{"fullName":"hs.chooser","description":"# hs.chooser","url":"hs.chooser.html","kind":"module"},{"fullName":"hs.chooser.create()","description":"Create a new chooser.","url":"hs.chooser.html#create","kind":"method"},{"fullName":"hs.docs","description":"# hs.docs","url":"hs.docs.html","kind":"module"},{"fullName":"hs.docs.show(moduleName, showTS)","description":"Open the Hammerspoon 2 API documentation in a new window","url":"hs.docs.html#show","kind":"method"},{"fullName":"hs.docs.get(identifier)","description":"Return documentation for a module, method, or property","url":"hs.docs.html#get","kind":"method"},{"fullName":"hs.docs.jsDocsPath()","description":"Return the filesystem path to the bundled JS documentation directory","url":"hs.docs.html#jsDocsPath","kind":"method"},{"fullName":"hs.docs.tsDocsPath()","description":"Return the filesystem path to the bundled TypeScript documentation directory","url":"hs.docs.html#tsDocsPath","kind":"method"},{"fullName":"hs.docs.apiJSON()","description":"Return the contents of the bundled api.json file","url":"hs.docs.html#apiJSON","kind":"method"},{"fullName":"hs.eventtap","description":"Monitor and synthesise macOS input events: keyboard, mouse, and scroll wheel.","url":"hs.eventtap.html","kind":"module"},{"fullName":"hs.eventtap.eventTypes","description":"A dictionary mapping event type names to their numeric values. Pass values from this dictionary to addWatcher() to specify which events to monitor.","url":"hs.eventtap.html#eventTypes","kind":"property"},{"fullName":"hs.eventtap.modifierFlags","description":"A dictionary mapping modifier key names to their bitmask values for use with rawFlags. Includes generic names (cmd, shift, alt, ctrl) and side-specific names (leftCmd, rightCmd, leftShift, rightShift, leftAlt, rightAlt, leftCtrl, rightCtrl) for distinguishing physical keys.","url":"hs.eventtap.html#modifierFlags","kind":"property"},{"fullName":"hs.eventtap.consume","description":"Return this from an event tap callback to suppress the event (prevent other apps from receiving it).","url":"hs.eventtap.html#consume","kind":"property"},{"fullName":"hs.eventtap.emit","description":"Return this from an event tap callback to allow the event to pass through to other applications.","url":"hs.eventtap.html#emit","kind":"property"},{"fullName":"hs.eventtap.addWatcher(types, callback, listenOnly)","description":"Create an event tap that calls a function for matching events. Call .start() to activate it. The callback receives an HSEventTapEvent. For modify taps (listenOnly omitted or false), return hs.eventtap.consume (false) to suppress the event or hs.eventtap.emit (true) to pass it through. For listen-only taps the callback's return value is ignored — events are always delivered to other applications. Requires Accessibility permission.","url":"hs.eventtap.html#addWatcher","kind":"method"},{"fullName":"hs.eventtap.removeWatcher(tap)","description":"Stop and remove a previously created watcher","url":"hs.eventtap.html#removeWatcher","kind":"method"},{"fullName":"hs.eventtap.makeKeyEvent(key, isDown)","description":"Create a keyboard event","url":"hs.eventtap.html#makeKeyEvent","kind":"method"},{"fullName":"hs.eventtap.makeKeyEventWithCode(keyCode, isDown)","description":"Create a keyboard event using a raw key code","url":"hs.eventtap.html#makeKeyEventWithCode","kind":"method"},{"fullName":"hs.eventtap.makeMouseEvent(type, x, y, button)","description":"Create a mouse event at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin of the primary display, y increases downward), matching the values returned by hs.screen.","url":"hs.eventtap.html#makeMouseEvent","kind":"method"},{"fullName":"hs.eventtap.makeScrollWheelEvent(deltaX, deltaY, x, y)","description":"Create a scroll wheel event at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#makeScrollWheelEvent","kind":"method"},{"fullName":"hs.eventtap.keyStroke(mods, key)","description":"Send a key down and key up event with optional modifier keys. A 50 ms pause is inserted between the key-down and key-up events to improve compatibility with applications that miss very fast synthetic keystrokes.","url":"hs.eventtap.html#keyStroke","kind":"method"},{"fullName":"hs.eventtap.keyStrokes(text)","description":"Type a string of characters as individual key events. A 50 ms pause is inserted between each key-down and key-up event.","url":"hs.eventtap.html#keyStrokes","kind":"method"},{"fullName":"hs.eventtap.leftClick(x, y)","description":"Post a left mouse button click at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#leftClick","kind":"method"},{"fullName":"hs.eventtap.rightClick(x, y)","description":"Post a right mouse button click at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#rightClick","kind":"method"},{"fullName":"hs.eventtap.doubleLeftClick(x, y)","description":"Post a left mouse button double-click at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#doubleLeftClick","kind":"method"},{"fullName":"hs.eventtap.middleClick(x, y)","description":"Post a middle mouse button click at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#middleClick","kind":"method"},{"fullName":"hs.eventtap.scrollWheel(deltaX, deltaY, x, y)","description":"Post a scroll wheel event at the given position. Coordinates are in Hammerspoon screen coordinates (top-left origin, y increases downward).","url":"hs.eventtap.html#scrollWheel","kind":"method"},{"fullName":"hs.eventtap.currentModifiers()","description":"Returns the currently held modifier keys","url":"hs.eventtap.html#currentModifiers","kind":"method"},{"fullName":"hs.eventtap.checkMouseButtons()","description":"Returns the currently pressed mouse buttons","url":"hs.eventtap.html#checkMouseButtons","kind":"method"},{"fullName":"hs.eventtap.mouseLocation()","description":"Returns the current mouse cursor position in Hammerspoon screen coordinates (top-left origin of primary display, y increases downward, matching hs.screen).","url":"hs.eventtap.html#mouseLocation","kind":"method"},{"fullName":"hs.eventtap.doubleClickInterval()","description":"Returns the system double-click interval in seconds","url":"hs.eventtap.html#doubleClickInterval","kind":"method"},{"fullName":"hs.eventtap.keyRepeatDelay()","description":"Returns the system key repeat delay in seconds","url":"hs.eventtap.html#keyRepeatDelay","kind":"method"},{"fullName":"hs.eventtap.keyRepeatInterval()","description":"Returns the system key repeat interval in seconds","url":"hs.eventtap.html#keyRepeatInterval","kind":"method"},{"fullName":"hs.eventtap.bindHotkey(mods, key, callbackPressed, callbackReleased)","description":"Bind a keyboard shortcut using an event tap. Unlike hs.hotkey.bind(), this supports the fn modifier and left/right modifier key distinction (e.g. leftCmd, rightAlt). The hotkey is active immediately and consumes (suppresses) the key events. It's important to note that this a much heavier-weight tool than hs.hotkey - every single key you press will be examined by Hammerspoon to see if it matches one of the EventTap hotkeys (where hs.hotkey relies on macOS to efficiently deliver only matching keypresses). Please consider this when choosing to use hs.eventtap for hotkeys. Requires Accessibility permission. ctrl, fn) and side-specific names (leftCmd, rightCmd, leftAlt, rightAlt, leftCtrl, rightCtrl, leftShift, rightShift).","url":"hs.eventtap.html#bindHotkey","kind":"method"},{"fullName":"hs.eventtap.removeHotkey(hotkey)","description":"Remove a previously bound hotkey and stop it from firing","url":"hs.eventtap.html#removeHotkey","kind":"method"},{"fullName":"hs.fs","description":"Module for filesystem operations.","url":"hs.fs.html","kind":"module"},{"fullName":"hs.fs.read(path, offset, length)","description":"Read part or all of a file as a UTF-8 string.","url":"hs.fs.html#read","kind":"method"},{"fullName":"hs.fs.readLines(path, callback)","description":"Read a file line-by-line, invoking a callback for each line. Lines are delivered with newline characters stripped. Both \\n and \\r\\n line endings are handled.","url":"hs.fs.html#readLines","kind":"method"},{"fullName":"hs.fs.write(path, content, inPlace)","description":"Write a UTF-8 string to a file, creating it or overwriting any existing content. Intermediate directories are not created automatically; use mkdir first if needed.","url":"hs.fs.html#write","kind":"method"},{"fullName":"hs.fs.append(path, content)","description":"Append a UTF-8 string to a file, creating it if it does not exist.","url":"hs.fs.html#append","kind":"method"},{"fullName":"hs.fs.exists(path)","description":"Determine if a filesystem object exists at the given path Unlike isFile and isDirectory, this follows symlinks.","url":"hs.fs.html#exists","kind":"method"},{"fullName":"hs.fs.isFile(path)","description":"Determine if a file exists at the given path This does not follow symlinks; a symlink pointing at a file returns false.","url":"hs.fs.html#isFile","kind":"method"},{"fullName":"hs.fs.isDirectory(path)","description":"Determine if a directory exists at the given path This does not follow symlinks; a symlink pointing at a directory returns false.","url":"hs.fs.html#isDirectory","kind":"method"},{"fullName":"hs.fs.isSymlink(path)","description":"Determine if a symlink exists at the given path","url":"hs.fs.html#isSymlink","kind":"method"},{"fullName":"hs.fs.isReadable(path)","description":"Determine if a given filesystem path is readable","url":"hs.fs.html#isReadable","kind":"method"},{"fullName":"hs.fs.isWritable(path)","description":"Determine if a given filesystem path is writable","url":"hs.fs.html#isWritable","kind":"method"},{"fullName":"hs.fs.copy(source, destination)","description":"Copy a file or directory to a new location. The destination must not already exist. If source is a directory, its entire contents are copied recursively.","url":"hs.fs.html#copy","kind":"method"},{"fullName":"hs.fs.move(source, destination)","description":"Move (rename) a file or directory. The destination must not already exist.","url":"hs.fs.html#move","kind":"method"},{"fullName":"hs.fs.deletePath(path)","description":"Delete a file or directory at the given path. Directories are removed recursively. To remove only an empty directory, use rmdir instead.","url":"hs.fs.html#deletePath","kind":"method"},{"fullName":"hs.fs.list(path)","description":"List the immediate contents of a directory. Returns bare filenames (not full paths), sorted alphabetically. The . and .. entries are never included.","url":"hs.fs.html#list","kind":"method"},{"fullName":"hs.fs.listRecursive(path)","description":"Recursively list all entries under a directory. Returns paths relative to path, sorted alphabetically.","url":"hs.fs.html#listRecursive","kind":"method"},{"fullName":"hs.fs.mkdir(path)","description":"Create a directory, including all necessary intermediate directories. Succeeds silently if the directory already exists.","url":"hs.fs.html#mkdir","kind":"method"},{"fullName":"hs.fs.rmdir(path)","description":"Remove an empty directory. Fails if the directory is not empty. Use deletePath to remove a non-empty directory recursively.","url":"hs.fs.html#rmdir","kind":"method"},{"fullName":"hs.fs.currentDir()","description":"Returns the current working directory of the process.","url":"hs.fs.html#currentDir","kind":"method"},{"fullName":"hs.fs.chdir(path)","description":"Change the current working directory of the process.","url":"hs.fs.html#chdir","kind":"method"},{"fullName":"hs.fs.pathToAbsolute(path)","description":"Resolve a path to its absolute, canonical form. Expands ~, resolves . and .., and follows all symbolic links. Returns null if any component of the path does not exist.","url":"hs.fs.html#pathToAbsolute","kind":"method"},{"fullName":"hs.fs.displayName(path)","description":"Return the localised display name for a file or directory as shown by Finder. For example, /Library appears as \"Library\" in Finder even though its on-disk name is the same.","url":"hs.fs.html#displayName","kind":"method"},{"fullName":"hs.fs.temporaryDirectory()","description":"Returns the temporary directory for the current user.","url":"hs.fs.html#temporaryDirectory","kind":"method"},{"fullName":"hs.fs.homeDirectory()","description":"Returns the home directory for the current user.","url":"hs.fs.html#homeDirectory","kind":"method"},{"fullName":"hs.fs.urlFromPath(path)","description":"Returns a file:// URL string for the given path.","url":"hs.fs.html#urlFromPath","kind":"method"},{"fullName":"hs.fs.attributes(path)","description":"Get metadata attributes for a file or directory. Does not follow symbolic links. Use isSymlink to detect links before calling this if needed.","url":"hs.fs.html#attributes","kind":"method"},{"fullName":"hs.fs.touch(path)","description":"Update the modification timestamp of a file to the current time. Creates the file if it does not exist (equivalent to the POSIX touch command).","url":"hs.fs.html#touch","kind":"method"},{"fullName":"hs.fs.link(source, destination)","description":"Create a hard link at destination pointing at source. Both paths must be on the same filesystem volume.","url":"hs.fs.html#link","kind":"method"},{"fullName":"hs.fs.symlink(source, destination)","description":"Create a symbolic link at destination pointing at source. Unlike hard links, symlinks may cross filesystem boundaries and may point to paths that do not yet exist.","url":"hs.fs.html#symlink","kind":"method"},{"fullName":"hs.fs.readlink(path)","description":"Read the target of a symbolic link without resolving it.","url":"hs.fs.html#readlink","kind":"method"},{"fullName":"hs.fs.tags(path)","description":"Get the Finder tags assigned to a file or directory.","url":"hs.fs.html#tags","kind":"method"},{"fullName":"hs.fs.fileUTI(path)","description":"Replace all Finder tags on a file or directory. This function is only available on macOS Tahoe (26) or later.","url":"hs.fs.html#fileUTI","kind":"method"},{"fullName":"hs.fs.pathToBookmark(path)","description":"Encode a file path as a persistent bookmark that survives file moves and renames. The returned string is base64-encoded bookmark data that can be stored and later resolved with pathFromBookmark.","url":"hs.fs.html#pathToBookmark","kind":"method"},{"fullName":"hs.fs.pathFromBookmark(data)","description":"Resolve a base64-encoded bookmark back to a file path.","url":"hs.fs.html#pathFromBookmark","kind":"method"},{"fullName":"hs.fs.volumes(showHidden)","description":"Return information about all currently mounted filesystem volumes.","url":"hs.fs.html#volumes","kind":"method"},{"fullName":"hs.fs.ejectVolume(path)","description":"Unmount and eject the volume at the given path.","url":"hs.fs.html#ejectVolume","kind":"method"},{"fullName":"hs.fs.addVolumeWatcher()","description":"Create a new volume event watcher. Call setCallback() and start() on the returned object to begin receiving volume mount/unmount/rename events.","url":"hs.fs.html#addVolumeWatcher","kind":"method"},{"fullName":"hs.fs.removeVolumeWatcher(watcher)","description":"Stop and destroy a volume watcher previously created with addVolumeWatcher.","url":"hs.fs.html#removeVolumeWatcher","kind":"method"},{"fullName":"hs.fs.xattrGet(path, attribute, options, position)","description":"Get the value of an extended attribute for a file or directory. Attribute values are returned as ISO Latin-1 encoded strings so that arbitrary byte sequences are represented without loss. ASCII text attribute values appear readable as-is.","url":"hs.fs.html#xattrGet","kind":"method"},{"fullName":"hs.fs.xattrList(path, options)","description":"List all extended attributes defined for a file or directory.","url":"hs.fs.html#xattrList","kind":"method"},{"fullName":"hs.fs.xattrSet(path, attribute, value, options, position)","description":"Set the value of an extended attribute for a file or directory. The value is written as ISO Latin-1 bytes, providing a lossless round-trip with xattrGet. Plain ASCII strings work directly without any encoding.","url":"hs.fs.html#xattrSet","kind":"method"},{"fullName":"hs.fs.xattrRemove(path, attribute, options)","description":"Remove an extended attribute from a file or directory.","url":"hs.fs.html#xattrRemove","kind":"method"},{"fullName":"hs.hash","description":"Module for hashing and encoding operations","url":"hs.hash.html","kind":"module"},{"fullName":"hs.hash.base64Encode(data)","description":"Encode a string to base64","url":"hs.hash.html#base64Encode","kind":"method"},{"fullName":"hs.hash.base64Decode(data)","description":"Decode a base64 string","url":"hs.hash.html#base64Decode","kind":"method"},{"fullName":"hs.hash.md5(data)","description":"Generate MD5 hash of a string","url":"hs.hash.html#md5","kind":"method"},{"fullName":"hs.hash.sha1(data)","description":"Generate SHA1 hash of a string","url":"hs.hash.html#sha1","kind":"method"},{"fullName":"hs.hash.sha256(data)","description":"Generate SHA256 hash of a string","url":"hs.hash.html#sha256","kind":"method"},{"fullName":"hs.hash.sha512(data)","description":"Generate SHA512 hash of a string","url":"hs.hash.html#sha512","kind":"method"},{"fullName":"hs.hash.hmacMD5(key, data)","description":"Generate HMAC-MD5 of a string with a key","url":"hs.hash.html#hmacMD5","kind":"method"},{"fullName":"hs.hash.hmacSHA1(key, data)","description":"Generate HMAC-SHA1 of a string with a key","url":"hs.hash.html#hmacSHA1","kind":"method"},{"fullName":"hs.hash.hmacSHA256(key, data)","description":"Generate HMAC-SHA256 of a string with a key","url":"hs.hash.html#hmacSHA256","kind":"method"},{"fullName":"hs.hash.hmacSHA512(key, data)","description":"Generate HMAC-SHA512 of a string with a key","url":"hs.hash.html#hmacSHA512","kind":"method"},{"fullName":"hs.hotkey","description":"Module for creating and managing system-wide hotkeys","url":"hs.hotkey.html","kind":"module"},{"fullName":"hs.hotkey.bind(mods, key, callbackPressed, callbackReleased)","description":"Bind a hotkey cmd / command / ⌘, shift / ⇧, alt / option / ⌥, ctrl / control / ⌃.","url":"hs.hotkey.html#bind","kind":"method"},{"fullName":"hs.hotkey.bindSpec(mods, key, message, callbackPressed, callbackReleased)","description":"Bind a hotkey with a message description","url":"hs.hotkey.html#bindSpec","kind":"method"},{"fullName":"hs.hotkey.getKeyCodeMap()","description":"Get the system-wide mapping of key names to key codes","url":"hs.hotkey.html#getKeyCodeMap","kind":"method"},{"fullName":"hs.hotkey.getModifierMap()","description":"Get the mapping of modifier names to modifier flags","url":"hs.hotkey.html#getModifierMap","kind":"method"},{"fullName":"hs.hotkey.create(mods, key, callbackPressed, callbackReleased)","description":"Create a hotkey without enabling it cmd / command / ⌘, shift / ⇧, alt / option / ⌥, ctrl / control / ⌃.","url":"hs.hotkey.html#create","kind":"method"},{"fullName":"hs.hotkey.createModal(mods, key)","description":"Create a new modal hotkey group, optionally entered via a trigger key combination","url":"hs.hotkey.html#createModal","kind":"method"},{"fullName":"hs.http","description":"HTTP client module for making network requests from JavaScript.","url":"hs.http.html","kind":"module"},{"fullName":"hs.http.get(url, headers)","description":"Perform an HTTP GET request.","url":"hs.http.html#get","kind":"method"},{"fullName":"hs.http.post(url, body, headers)","description":"Perform an HTTP POST request.","url":"hs.http.html#post","kind":"method"},{"fullName":"hs.http.put(url, body, headers)","description":"Perform an HTTP PUT request.","url":"hs.http.html#put","kind":"method"},{"fullName":"hs.http.doRequest(url, method, body, headers)","description":"Perform an HTTP request with any method (GET, POST, PUT, DELETE, PATCH, etc.). Use this for methods not covered by the convenience helpers, such as DELETE or PATCH.","url":"hs.http.html#doRequest","kind":"method"},{"fullName":"hs.http.encodeForQuery(string)","description":"URL-encode a string for use as a query parameter value. Encodes characters that are illegal in a URL query string (including ?, =, +, &, #) using percent-encoding.","url":"hs.http.html#encodeForQuery","kind":"method"},{"fullName":"hs.http.urlParts(url)","description":"Parse a URL into its component parts. Returns an object containing only the fields present in the URL. The queryItems field is an array of {name, value} objects from the query string.","url":"hs.http.html#urlParts","kind":"method"},{"fullName":"hs.http.convertHtmlEntities(string)","description":"Convert HTML entities in a string to their UTF-8 character equivalents. Handles named entities (e.g. &, <, ©), decimal numeric references (&), and hexadecimal numeric references (&).","url":"hs.http.html#convertHtmlEntities","kind":"method"},{"fullName":"hs.http.openWebSocket(url)","description":"Open a WebSocket connection to the given URL. The connection begins immediately. Use the returned object's chainable setter methods to register event callbacks. The connection is automatically closed when hs.reload() is called or the engine shuts down.","url":"hs.http.html#openWebSocket","kind":"method"},{"fullName":"hs.httpserver","description":"Module for creating and managing HTTP servers.","url":"hs.httpserver.html","kind":"module"},{"fullName":"hs.httpserver.create()","description":"Create a new HTTP server instance. The server is not running until you call start() on the returned object.","url":"hs.httpserver.html#create","kind":"method"},{"fullName":"hs.ipc","description":"Module for enabling CLI access to Hammerspoon 2 via the hs command-line tool.","url":"hs.ipc.html","kind":"module"},{"fullName":"hs.ipc.isListening","description":"Whether the IPC server is currently accepting connections.","url":"hs.ipc.html#isListening","kind":"property"},{"fullName":"hs.ipc.start()","description":"Start the IPC server. The server listens on a named XPC Mach service (net.tenshu.Hammerspoon-2.ipc). In release builds, only processes signed with the same Team ID can connect. Calling start() when already running logs a warning and does nothing.","url":"hs.ipc.html#start","kind":"method"},{"fullName":"hs.ipc.stop()","description":"Stop the IPC server and disconnect all connected clients.","url":"hs.ipc.html#stop","kind":"method"},{"fullName":"hs.ipc.installBinary(directory)","description":"Install the hs command-line tool to the given directory as a symlink. Creates a symlink in the target directory that points to the hs binary inside the Hammerspoon 2 app bundle. Using a symlink means the CLI automatically reflects any app update without reinstalling. Any existing hs file at that path is replaced. The directory must be on your $PATH for hs to work without a full path. Permissions: /usr/local/bin is typically user-writable on Intel Macs with Homebrew. On Apple Silicon, prefer /opt/homebrew/bin. On a stock Mac (no Homebrew), both directories require root — if this method returns false, run the logged command in a terminal with sudo.","url":"hs.ipc.html#installBinary","kind":"method"},{"fullName":"hs.ipc.uninstallBinary(directory)","description":"Remove the hs command-line tool from the given directory.","url":"hs.ipc.html#uninstallBinary","kind":"method"},{"fullName":"hs.ipc.isBinaryInstalled(directory)","description":"Check whether the hs command-line tool exists at the given directory.","url":"hs.ipc.html#isBinaryInstalled","kind":"method"},{"fullName":"hs.keycodes","description":"Access information about the current keyboard layout and input sources, and respond to changes.","url":"hs.keycodes.html","kind":"module"},{"fullName":"hs.keycodes.map","description":"A bidirectional mapping between key names and their macOS virtual key codes. Entries exist for both directions: look up a name to get its integer keycode, or look up a keycode (as a string) to get the key name. The map is rebuilt automatically whenever the keyboard input source changes.","url":"hs.keycodes.html#map","kind":"property"},{"fullName":"hs.keycodes.currentLayout()","description":"Returns the localized name of the current keyboard layout. Uses the base keyboard layout, which is the underlying layout even when an input method (such as a CJK input method) is also active.","url":"hs.keycodes.html#currentLayout","kind":"method"},{"fullName":"hs.keycodes.currentMethod()","description":"Returns the localized name of the active input method, or null if none is active. Input methods are distinct from keyboard layouts. They provide complex character composition such as CJK input. Returns null when using a plain keyboard layout with no input method overlay.","url":"hs.keycodes.html#currentMethod","kind":"method"},{"fullName":"hs.keycodes.currentSourceID()","description":"Returns the reverse-DNS identifier of the currently selected keyboard input source.","url":"hs.keycodes.html#currentSourceID","kind":"method"},{"fullName":"hs.keycodes.layouts()","description":"Returns the localized names of all currently enabled keyboard layouts.","url":"hs.keycodes.html#layouts","kind":"method"},{"fullName":"hs.keycodes.methods()","description":"Returns the localized names of all currently enabled input methods.","url":"hs.keycodes.html#methods","kind":"method"},{"fullName":"hs.keycodes.setLayout(layoutName)","description":"Switches the active keyboard layout to the one with the given localized name. Use layouts() to enumerate valid names.","url":"hs.keycodes.html#setLayout","kind":"method"},{"fullName":"hs.keycodes.setMethod(methodName)","description":"Switches the active input method to the one with the given localized name. Use methods() to enumerate valid names.","url":"hs.keycodes.html#setMethod","kind":"method"},{"fullName":"hs.keycodes.setSourceID(sourceID)","description":"Switches the active input source to the one with the given reverse-DNS identifier. Use currentSourceID() to see the current value.","url":"hs.keycodes.html#setSourceID","kind":"method"},{"fullName":"hs.keycodes.addWatcher(listener)","description":"Registers a listener that fires whenever the keyboard input source changes. The listener is called with no arguments. Read currentLayout(), currentSourceID(), or map inside the callback to inspect the new state. The OS subscription starts lazily on the first listener and is released automatically when the last listener is removed via removeWatcher.","url":"hs.keycodes.html#addWatcher","kind":"method"},{"fullName":"hs.keycodes.removeWatcher(listener)","description":"Removes a previously registered input source change listener.","url":"hs.keycodes.html#removeWatcher","kind":"method"},{"fullName":"hs.location","description":"Determine the Mac's location via macOS Location Services.","url":"hs.location.html","kind":"module"},{"fullName":"hs.location.lookupAddress(address)","description":"Geocodes an address string into an array of placemarkTables. Returns a Promise that resolves with an array of placemarkTable objects (sorted by relevance) or rejects with an error message.","url":"hs.location.html#lookupAddress","kind":"method"},{"fullName":"hs.location.lookupLocation(locationTable)","description":"Reverse-geocodes a locationTable into an array of placemarkTables. Returns a Promise that resolves with matching placemarks or rejects with an error.","url":"hs.location.html#lookupLocation","kind":"method"},{"fullName":"hs.location.servicesEnabled()","description":"Returns true if Location Services are enabled system-wide.","url":"hs.location.html#servicesEnabled","kind":"method"},{"fullName":"hs.location.authorizationStatus()","description":"Returns the app's current Location Services authorization status as a string.","url":"hs.location.html#authorizationStatus","kind":"method"},{"fullName":"hs.location.get()","description":"Returns the most recently cached location as a locationTable, or null. Activates Location Services if not already running. The cache is updated periodically while any watcher is running.","url":"hs.location.html#get","kind":"method"},{"fullName":"hs.location.distance(from, to)","description":"Calculates the straight-line distance in metres between two locationTables. Does not require Location Services.","url":"hs.location.html#distance","kind":"method"},{"fullName":"hs.location.sunrise(latitude, longitude, date)","description":"Returns the time of sunrise for the given coordinates and date, or null if the sun does not rise on that date (polar night).","url":"hs.location.html#sunrise","kind":"method"},{"fullName":"hs.location.sunset(latitude, longitude, date)","description":"Returns the time of sunset for the given coordinates and date, or null if the sun does not set on that date (midnight sun).","url":"hs.location.html#sunset","kind":"method"},{"fullName":"hs.location.addWatcher()","description":"Creates a new location watcher object. Call .start() on it to begin receiving updates. The watcher is automatically stopped when the module shuts down.","url":"hs.location.html#addWatcher","kind":"method"},{"fullName":"hs.location.removeWatcher(watcher)","description":"Removes a previously created watcher and stops it if running.","url":"hs.location.html#removeWatcher","kind":"method"},{"fullName":"hs.menubar","description":"Module for creating and managing macOS system menu bar items.","url":"hs.menubar.html","kind":"module"},{"fullName":"hs.menubar.create(hidden)","description":"Create a new menu bar item","url":"hs.menubar.html#create","kind":"method"},{"fullName":"hs.mouse","description":"Control and inspect the mouse pointer and attached mouse devices.","url":"hs.mouse.html","kind":"module"},{"fullName":"hs.mouse.absolutePosition()","description":"Returns the current mouse pointer position in Hammerspoon screen coordinates. Hammerspoon coordinates have (0, 0) at the top-left of the primary display, with y increasing downward.","url":"hs.mouse.html#absolutePosition","kind":"method"},{"fullName":"hs.mouse.setAbsolutePosition(x, y)","description":"Moves the mouse pointer to the specified absolute position in Hammerspoon screen coordinates.","url":"hs.mouse.html#setAbsolutePosition","kind":"method"},{"fullName":"hs.mouse.getRelativePosition()","description":"Returns the mouse pointer position relative to the screen it is currently on. The returned coordinates have (0, 0) at the top-left corner of the screen that the cursor is on.","url":"hs.mouse.html#getRelativePosition","kind":"method"},{"fullName":"hs.mouse.setRelativePosition(x, y)","description":"Moves the mouse pointer to a position relative to the screen it is currently on.","url":"hs.mouse.html#setRelativePosition","kind":"method"},{"fullName":"hs.mouse.getCurrentScreen()","description":"Returns the screen that the mouse pointer is currently on.","url":"hs.mouse.html#getCurrentScreen","kind":"method"},{"fullName":"hs.mouse.count(includeInternal)","description":"Returns the number of mouse devices currently attached to the system.","url":"hs.mouse.html#count","kind":"method"},{"fullName":"hs.mouse.names(includeInternal)","description":"Returns the product names of all mouse devices currently attached to the system.","url":"hs.mouse.html#names","kind":"method"},{"fullName":"hs.mouse.trackingSpeed()","description":"Returns the current mouse tracking speed (acceleration level). Values range from -1.0 (system default, acceleration disabled) to 3.0 (maximum acceleration). Returns -1.0 if the value cannot be read.","url":"hs.mouse.html#trackingSpeed","kind":"method"},{"fullName":"hs.mouse.setTrackingSpeed(speed)","description":"Sets the mouse tracking speed (acceleration level). The change takes effect immediately for the current login session and is also persisted to preferences so it survives a restart. Values outside the valid range or non-finite values are rejected with a warning and no change is made.","url":"hs.mouse.html#setTrackingSpeed","kind":"method"},{"fullName":"hs.mouse.scrollDirection()","description":"Returns the current scroll wheel direction setting.","url":"hs.mouse.html#scrollDirection","kind":"method"},{"fullName":"hs.mouse.currentCursorType()","description":"Returns the name of the cursor type currently set by this application. has the keyboard focus, the visible system cursor may differ.","url":"hs.mouse.html#currentCursorType","kind":"method"},{"fullName":"hs.network","description":"Module for inspecting network interfaces, resolving hostnames, and reading system configuration","url":"hs.network.html","kind":"module"},{"fullName":"hs.network.reachabilityFlags","description":"A dictionary of named flag constants for use with HSNetworkReachability.status(). Compare individual bits against these constants to determine which network conditions apply. The numeric values match the deprecated SCNetworkReachabilityFlags for backward compatibility. Keys: transientConnection, reachable, connectionRequired, connectionOnTraffic, interventionRequired, connectionOnDemand, isLocalAddress, isDirect.","url":"hs.network.html#reachabilityFlags","kind":"property"},{"fullName":"hs.network.interfaces()","description":"Returns all network interfaces present on this system. Each object contains name (string), isLoopback (boolean), isUp (boolean), and isRunning (boolean). A displayName string is included when the system provides a human-readable label for the interface (e.g. \"Wi-Fi\" or \"Ethernet\").","url":"hs.network.html#interfaces","kind":"method"},{"fullName":"hs.network.primaryInterface()","description":"Returns the name of the primary network interface, i.e. the one currently providing the default route.","url":"hs.network.html#primaryInterface","kind":"method"},{"fullName":"hs.network.addresses()","description":"Returns all IP addresses assigned to this host. Each object contains interface (the BSD name of the interface), address (the address string), and family (\"ipv4\" or \"ipv6\").","url":"hs.network.html#addresses","kind":"method"},{"fullName":"hs.network.resolve(hostname, family)","description":"Asynchronously resolves a hostname to its IP addresses using the system DNS resolver. Uses CFHost, which respects the system's network configuration including VPN routes and proxy settings.","url":"hs.network.html#resolve","kind":"method"},{"fullName":"hs.network.reachabilityForAddress(address)","description":"Creates a reachability monitor for a specific IP address. Returns null if address is not a valid IPv4 or IPv6 address literal. Under the hood this monitors general system connectivity (the same as reachabilityInternet()), because NWPathMonitor does not support per-address targeting.","url":"hs.network.html#reachabilityForAddress","kind":"method"},{"fullName":"hs.network.reachabilityForAddressPair(localAddress, remoteAddress)","description":"Creates a reachability monitor for a source/destination IP address pair. Returns null if either address is not a valid IPv4 or IPv6 address literal. Under the hood this monitors general system connectivity (the same as reachabilityInternet()), because NWPathMonitor does not support per-address targeting.","url":"hs.network.html#reachabilityForAddressPair","kind":"method"},{"fullName":"hs.network.reachabilityForHostName(hostName)","description":"Creates a reachability monitor for a given hostname. Returns null if hostName is empty. Under the hood this monitors general system connectivity (the same as reachabilityInternet()), because NWPathMonitor does not support per-hostname targeting.","url":"hs.network.html#reachabilityForHostName","kind":"method"},{"fullName":"hs.network.reachabilityInternet()","description":"Creates a reachability monitor for general internet connectivity. This is the most common factory method. Use it when you want to know whether the device currently has a working internet connection.","url":"hs.network.html#reachabilityInternet","kind":"method"},{"fullName":"hs.network.reachabilityLinkLocal()","description":"Creates a reachability monitor for link-local connectivity. Link-local addresses cover the 169.254.x.x (IPv4) and fe80::/10 (IPv6) ranges used for direct device-to-device communication without a router. Under the hood this monitors general system connectivity (the same as reachabilityInternet()), because NWPathMonitor does not distinguish link-local reachability.","url":"hs.network.html#reachabilityLinkLocal","kind":"method"},{"fullName":"hs.network.configurationStore(pattern)","description":"Returns the contents of the macOS System Configuration dynamic store as a dictionary. The store holds live network configuration for the running system — interface addresses, routing, DNS servers, proxy settings, VPN state, and more. Keys follow a hierarchical path convention (e.g. \"State:/Network/Global/IPv4\"). Omit or pass null to return all keys (equivalent to \".*\").","url":"hs.network.html#configurationStore","kind":"method"},{"fullName":"hs.network.configurationLocations()","description":"Returns a mapping of all configured network location UUIDs to their display names. Use this to discover available locations before calling configurationSetLocation().","url":"hs.network.html#configurationLocations","kind":"method"},{"fullName":"hs.network.configurationSetLocation(location)","description":"Switches the active network location to the one with the given name or UUID. Pass the location's display name (e.g. \"Home\") or its UUID from configurationLocations(). The change is applied immediately. Returns false if the location was not found or the preferences could not be committed (e.g. insufficient privileges).","url":"hs.network.html#configurationSetLocation","kind":"method"},{"fullName":"hs.network.configurationWatcher()","description":"Creates a watcher that fires a callback when System Configuration dynamic store keys change. Call setKeys() to specify which keys (or patterns) to watch, setCallback() to register the handler, then start() to begin monitoring. The module automatically stops and destroys all watchers on hs.reload().","url":"hs.network.html#configurationWatcher","kind":"method"},{"fullName":"hs.network.ping(server, options)","description":"Sends ICMP Echo Requests to server and reports results via a callback. DNS resolution and the first ping begin immediately. The returned object can be used to pause, resume, or cancel the ping, and to read statistics. timeout (seconds per packet, default 2.0), family (\"any\" | \"ipv4\" | \"ipv6\", default \"any\"), and callback (function).","url":"hs.network.html#ping","kind":"method"},{"fullName":"hs.notify","description":"Module for creating and displaying macOS system notifications.","url":"hs.notify.html","kind":"module"},{"fullName":"hs.notify.show(title, body, callback)","description":"Display a notification immediately.","url":"hs.notify.html#show","kind":"method"},{"fullName":"hs.notify.create(options)","description":"Create a richly configured notification without sending it yet.","url":"hs.notify.html#create","kind":"method"},{"fullName":"hs.notify.removeAllDelivered()","description":"Remove all delivered Hammerspoon notifications from Notification Center.","url":"hs.notify.html#removeAllDelivered","kind":"method"},{"fullName":"hs.notify.removeAllPending()","description":"Cancel all pending (not yet delivered) Hammerspoon notifications.","url":"hs.notify.html#removeAllPending","kind":"method"},{"fullName":"hs.ocr","description":"Recognize text in images using Apple's Vision framework.","url":"hs.ocr.html","kind":"module"},{"fullName":"hs.ocr.recognizeText(path, options)","description":"Recognize text in the image at the given file path. Returns a Promise that resolves with an HSOCRResult containing all recognized text and per-region observations. The image must exist on disk; URLs and data buffers are not supported. Recognition is performed on a background thread; the main thread is not blocked during the operation. \"accurate\" uses a larger neural network for better results; \"fast\" trades accuracy for speed. Observations whose confidence is below this threshold are excluded from result.observations (and therefore from result.text). Hints Vision toward specific languages. Use supportedLanguages() to enumerate the available codes for the current device. When true, Vision selects recognition languages automatically. Overrides languages when set.","url":"hs.ocr.html#recognizeText","kind":"method"},{"fullName":"hs.ocr.supportedLanguages()","description":"Returns the BCP-47 language codes supported by the Vision text recognizer on this device. The set of languages varies between macOS versions and hardware. Call this at runtime to discover which codes are valid for the languages option passed to recognizeText().","url":"hs.ocr.html#supportedLanguages","kind":"method"},{"fullName":"hs.osascript","description":"Run AppleScript and OSA JavaScript from Hammerspoon scripts.","url":"hs.osascript.html","kind":"module"},{"fullName":"hs.osascript.applescript(source)","description":"Run an AppleScript source string.","url":"hs.osascript.html#applescript","kind":"method"},{"fullName":"hs.osascript.javascript(source)","description":"Run an OSA JavaScript source string. OSA JavaScript is Apple's Open Scripting Architecture dialect of JavaScript, distinct from the JavaScriptCore engine that runs Hammerspoon scripts themselves.","url":"hs.osascript.html#javascript","kind":"method"},{"fullName":"hs.osascript.applescriptFromFile(path)","description":"Read a file from disk and execute its contents as AppleScript. The file is read in the main process before being sent to the XPC helper. If the file cannot be read the promise resolves immediately with { success: false, result: null, raw: \"Failed to read file: \" }.","url":"hs.osascript.html#applescriptFromFile","kind":"method"},{"fullName":"hs.osascript.javascriptFromFile(path)","description":"Read a file from disk and execute its contents as OSA JavaScript. The file is read in the main process before being sent to the XPC helper. If the file cannot be read the promise resolves immediately with { success: false, result: null, raw: \"Failed to read file: \" }.","url":"hs.osascript.html#javascriptFromFile","kind":"method"},{"fullName":"hs.osascript._execute(source, language)","description":"Low-level execution entry point used by the higher-level helpers. Prefer applescript() or javascript() over calling this directly.","url":"hs.osascript.html#_execute","kind":"method"},{"fullName":"hs.osascript.applescriptSync(source)","description":"Run an AppleScript source string synchronously. Blocks the JS thread until the script completes.","url":"hs.osascript.html#applescriptSync","kind":"method"},{"fullName":"hs.osascript.javascriptSync(source)","description":"Run an OSA JavaScript source string synchronously. Blocks the JS thread until the script completes.","url":"hs.osascript.html#javascriptSync","kind":"method"},{"fullName":"hs.osascript.applescriptSyncFromFile(path)","description":"Read a file from disk and execute its contents as AppleScript synchronously.","url":"hs.osascript.html#applescriptSyncFromFile","kind":"method"},{"fullName":"hs.osascript.javascriptSyncFromFile(path)","description":"Read a file from disk and execute its contents as OSA JavaScript synchronously.","url":"hs.osascript.html#javascriptSyncFromFile","kind":"method"},{"fullName":"hs.osascript._executeSync(source, language)","description":"Low-level synchronous execution entry point. Prefer applescriptSync() or javascriptSync() over calling this directly.","url":"hs.osascript.html#_executeSync","kind":"method"},{"fullName":"hs.pasteboard","description":"Module for interacting with the macOS pasteboard (clipboard)","url":"hs.pasteboard.html","kind":"module"},{"fullName":"hs.pasteboard.changeCount","description":"The pasteboard change count. Increments each time any application writes to the pasteboard. Comparing a saved value to the current value is the standard way to detect external changes.","url":"hs.pasteboard.html#changeCount","kind":"property"},{"fullName":"hs.pasteboard.watcherInterval","description":"The polling interval for the pasteboard watcher, in seconds. Defaults to 0.5. Changes take effect the next time a watcher is started (i.e. after removing and re-adding).","url":"hs.pasteboard.html#watcherInterval","kind":"property"},{"fullName":"hs.pasteboard.readString()","description":"Read plain text from the pasteboard","url":"hs.pasteboard.html#readString","kind":"method"},{"fullName":"hs.pasteboard.readHTML()","description":"Read HTML from the pasteboard","url":"hs.pasteboard.html#readHTML","kind":"method"},{"fullName":"hs.pasteboard.readRTF()","description":"Read RTF from the pasteboard","url":"hs.pasteboard.html#readRTF","kind":"method"},{"fullName":"hs.pasteboard.readURL()","description":"Read a URL from the pasteboard","url":"hs.pasteboard.html#readURL","kind":"method"},{"fullName":"hs.pasteboard.readImage()","description":"Read an image from the pasteboard","url":"hs.pasteboard.html#readImage","kind":"method"},{"fullName":"hs.pasteboard.readData(uti)","description":"Read raw data for a specific UTI type, returned as a base64-encoded string. Use this for types not covered by the convenience read methods.","url":"hs.pasteboard.html#readData","kind":"method"},{"fullName":"hs.pasteboard.writeString(str)","description":"Write plain text to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeString","kind":"method"},{"fullName":"hs.pasteboard.writeHTML(html)","description":"Write HTML to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeHTML","kind":"method"},{"fullName":"hs.pasteboard.writeRTF(rtf)","description":"Write RTF to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeRTF","kind":"method"},{"fullName":"hs.pasteboard.writeURL(url)","description":"Write a URL to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeURL","kind":"method"},{"fullName":"hs.pasteboard.writeImage(image)","description":"Write an image to the pasteboard, replacing all current contents","url":"hs.pasteboard.html#writeImage","kind":"method"},{"fullName":"hs.pasteboard.writeData(base64, uti)","description":"Write raw base64-encoded data for a specific UTI type, replacing all current contents. Use this for types not covered by the convenience write methods.","url":"hs.pasteboard.html#writeData","kind":"method"},{"fullName":"hs.pasteboard.writeObjects(representations)","description":"Write multiple type representations to the pasteboard atomically, replacing all current contents. Keys must be UTI type strings; values must be strings. This is how you provide both a plain-text fallback and a richer representation (such as HTML) in a single clipboard operation.","url":"hs.pasteboard.html#writeObjects","kind":"method"},{"fullName":"hs.pasteboard.types()","description":"Get all UTI type strings currently on the pasteboard, across all items","url":"hs.pasteboard.html#types","kind":"method"},{"fullName":"hs.pasteboard.hasType(uti)","description":"Check whether a specific UTI type is currently available on the pasteboard","url":"hs.pasteboard.html#hasType","kind":"method"},{"fullName":"hs.pasteboard.clear()","description":"Clear all contents from the pasteboard","url":"hs.pasteboard.html#clear","kind":"method"},{"fullName":"hs.pasteboard.addWatcher(listener)","description":"Add a watcher that is called whenever the pasteboard contents change. Multiple watchers may be registered; they are each called independently. Because macOS provides no pasteboard change notification API, this is implemented by polling changeCount at the interval specified by watcherInterval.","url":"hs.pasteboard.html#addWatcher","kind":"method"},{"fullName":"hs.pasteboard.removeWatcher(listener)","description":"Remove a previously registered pasteboard watcher","url":"hs.pasteboard.html#removeWatcher","kind":"method"},{"fullName":"hs.permissions","description":"Module for checking and requesting system permissions","url":"hs.permissions.html","kind":"module"},{"fullName":"hs.permissions.checkAccessibility()","description":"Check if the app has Accessibility permission","url":"hs.permissions.html#checkAccessibility","kind":"method"},{"fullName":"hs.permissions.requestAccessibility()","description":"Request Accessibility permission (shows system dialog if not granted)","url":"hs.permissions.html#requestAccessibility","kind":"method"},{"fullName":"hs.permissions.checkScreenRecording()","description":"Check if the app has Screen Recording permission","url":"hs.permissions.html#checkScreenRecording","kind":"method"},{"fullName":"hs.permissions.requestScreenRecording()","description":"Request Screen Recording permission","url":"hs.permissions.html#requestScreenRecording","kind":"method"},{"fullName":"hs.permissions.checkCamera()","description":"Check if the app has Camera permission","url":"hs.permissions.html#checkCamera","kind":"method"},{"fullName":"hs.permissions.requestCamera()","description":"Request Camera permission (shows system dialog if not granted)","url":"hs.permissions.html#requestCamera","kind":"method"},{"fullName":"hs.permissions.checkMicrophone()","description":"Check if the app has Microphone permission","url":"hs.permissions.html#checkMicrophone","kind":"method"},{"fullName":"hs.permissions.requestMicrophone()","description":"Request Microphone permission (shows system dialog if not granted)","url":"hs.permissions.html#requestMicrophone","kind":"method"},{"fullName":"hs.permissions.checkNotifications()","description":"Check if the app has permission to display notifications. The result is cached from the last request or check; the cache is refreshed asynchronously, so the very first call in a session may return false before the cached value is populated. Use requestNotifications() on first launch to ensure the result is accurate.","url":"hs.permissions.html#checkNotifications","kind":"method"},{"fullName":"hs.permissions.requestNotifications()","description":"Request notification permission (shows the system dialog if the user has not yet decided). It is safe to call this on every launch — the dialog only appears once; subsequent calls resolve immediately with the previously granted or denied state.","url":"hs.permissions.html#requestNotifications","kind":"method"},{"fullName":"hs.permissions.checkLocation()","description":"Check if the app has Location permission.","url":"hs.permissions.html#checkLocation","kind":"method"},{"fullName":"hs.permissions.requestLocation()","description":"Request Location permission (shows the system dialog if the user has not yet decided).","url":"hs.permissions.html#requestLocation","kind":"method"},{"fullName":"hs.power","description":"Monitor and control system power: prevent sleep, read battery state, respond to power events, and lock or sleep the machine.","url":"hs.power.html","kind":"module"},{"fullName":"hs.power.percentage","description":"The current battery charge percentage (0–100), or -1 if no battery is present.","url":"hs.power.html#percentage","kind":"property"},{"fullName":"hs.power.isCharging","description":"Whether the battery is currently charging. Returns false when no battery is present.","url":"hs.power.html#isCharging","kind":"property"},{"fullName":"hs.power.powerSource","description":"The current power source. Returns \"ac\" when plugged in, \"battery\" when on battery power, \"ups\" when powered by a UPS, or \"unknown\" if the source cannot be determined.","url":"hs.power.html#powerSource","kind":"property"},{"fullName":"hs.power.isLowPowerMode","description":"Whether Low Power Mode is currently active.","url":"hs.power.html#isLowPowerMode","kind":"property"},{"fullName":"hs.power.thermalState","description":"The current thermal state of the system. Returns one of: \"nominal\", \"fair\", \"serious\", \"critical\".","url":"hs.power.html#thermalState","kind":"property"},{"fullName":"hs.power.preventSleep(type)","description":"Prevents the specified type of system sleep. Creates an IOKit power assertion that stops macOS from allowing the specified type of sleep. Call allowSleep with the same type to release the assertion. idle sleep), \"systemIdle\" (prevent system idle sleep), \"system\" (prevent all system sleep, including from power button or lid close).","url":"hs.power.html#preventSleep","kind":"method"},{"fullName":"hs.power.allowSleep(type)","description":"Releases a previously created sleep prevention assertion.","url":"hs.power.html#allowSleep","kind":"method"},{"fullName":"hs.power.isSleepPrevented(type)","description":"Returns whether Hammerspoon is currently preventing the specified type of sleep.","url":"hs.power.html#isSleepPrevented","kind":"method"},{"fullName":"hs.power.declareActivity()","description":"Simulates user activity, briefly resetting the display idle timer. Equivalent to moving the mouse — does not create a persistent assertion.","url":"hs.power.html#declareActivity","kind":"method"},{"fullName":"hs.power.currentAssertions()","description":"Returns the active power management assertions from all processes on the system.","url":"hs.power.html#currentAssertions","kind":"method"},{"fullName":"hs.power.systemSleep()","description":"Puts the system to sleep immediately. Requires the Automation permission for System Events.","url":"hs.power.html#systemSleep","kind":"method"},{"fullName":"hs.power.lockScreen()","description":"Locks the screen immediately.","url":"hs.power.html#lockScreen","kind":"method"},{"fullName":"hs.power.startScreensaver()","description":"Starts the screensaver immediately.","url":"hs.power.html#startScreensaver","kind":"method"},{"fullName":"hs.power.batteryInfo()","description":"Returns a snapshot of all available battery information, or null if no battery is present.","url":"hs.power.html#batteryInfo","kind":"method"},{"fullName":"hs.power.addEventWatcher(listener)","description":"Registers a listener that fires when system power events occur. \"screensDidSleep\", \"screensDidWake\", \"screensDidLock\", \"screensDidUnlock\", \"screensaverDidStart\", \"screensaverDidStop\", \"screensaverWillStop\", \"systemWillSleep\", \"systemDidWake\", \"systemWillPowerOff\", \"sessionDidBecomeActive\", \"sessionDidResignActive\". The OS notification subscription starts lazily on the first listener and is released automatically when the last listener is removed.","url":"hs.power.html#addEventWatcher","kind":"method"},{"fullName":"hs.power.removeEventWatcher(listener)","description":"Removes a previously registered power event listener.","url":"hs.power.html#removeEventWatcher","kind":"method"},{"fullName":"hs.power.addBatteryWatcher(listener)","description":"Registers a listener that fires whenever battery state changes. The listener receives no arguments; call batteryInfo() or read individual properties inside the callback to determine what changed. The OS notification subscription starts lazily on the first listener and is released automatically when the last listener is removed.","url":"hs.power.html#addBatteryWatcher","kind":"method"},{"fullName":"hs.power.removeBatteryWatcher(listener)","description":"Removes a previously registered battery change listener.","url":"hs.power.html#removeBatteryWatcher","kind":"method"},{"fullName":"hs.screen","description":"Inspect and control the displays attached to the system.","url":"hs.screen.html","kind":"module"},{"fullName":"hs.screen.all()","description":"All connected screens.","url":"hs.screen.html#all","kind":"method"},{"fullName":"hs.screen.main()","description":"The screen that currently contains the focused window, or the screen with the keyboard focus if no window is focused.","url":"hs.screen.html#main","kind":"method"},{"fullName":"hs.screen.primary()","description":"The primary display — the one that contains the global menu bar.","url":"hs.screen.html#primary","kind":"method"},{"fullName":"hs.shortcuts","description":"Run and interact with macOS Shortcuts from JavaScript.","url":"hs.shortcuts.html","kind":"module"},{"fullName":"hs.shortcuts.list()","description":"Returns an array of all available shortcuts. | Key | Type | Description | |-----|------|-------------| | name | string | The display name of the shortcut | | id | string | A UUID uniquely identifying the shortcut | | acceptsInput | boolean | Whether the shortcut expects input when run | | actionCount | number | How many actions the shortcut contains |","url":"hs.shortcuts.html#list","kind":"method"},{"fullName":"hs.shortcuts.run(name)","description":"Runs a Shortcuts shortcut by name and returns any output. Executes the shortcut in the background via the shortcuts CLI tool. If the shortcut produces output (via a \"Stop and Output\" action), the Promise resolves with that string. If the shortcut produces no output, the Promise resolves with null. The Promise rejects if the shortcut cannot be found or exits with a non-zero status.","url":"hs.shortcuts.html#run","kind":"method"},{"fullName":"hs.shortcuts.open(name)","description":"Opens a shortcut in the Shortcuts app for viewing or editing. Uses the shortcuts://open-shortcut URL scheme to bring Shortcuts to the foreground and navigate directly to the named shortcut.","url":"hs.shortcuts.html#open","kind":"method"},{"fullName":"hs.sound","description":"Play audio from files on disk or from the system's built-in sound library.","url":"hs.sound.html","kind":"module"},{"fullName":"hs.sound.fromFile(path)","description":"Loads an audio file from the given path and returns a sound object. Returns null if the file cannot be loaded.","url":"hs.sound.html#fromFile","kind":"method"},{"fullName":"hs.sound.named(name)","description":"Creates a sound object for a built-in system sound by name. Returns null if no sound with that name can be found. Use hs.sound.systemSounds() to discover available names.","url":"hs.sound.html#named","kind":"method"},{"fullName":"hs.sound.systemSounds()","description":"Returns a sorted array of all available system sound names. These names can be passed directly to hs.sound.named(). Scans /System/Library/Sounds, /Library/Sounds, and ~/Library/Sounds.","url":"hs.sound.html#systemSounds","kind":"method"},{"fullName":"hs.spotlight","description":"Query the macOS Spotlight metadata database.","url":"hs.spotlight.html","kind":"module"},{"fullName":"hs.spotlight.scope","description":"Predefined search scope constants for use with HSSpotlightQuery.setScopes(). | Key | Description | |-----|-------------| | home | The current user's home directory | | computer | All locally mounted volumes | | network | Network-mounted volumes | | applications | Common locations for .app bundles | | icloud | iCloud Documents | | icloudData | iCloud Data (non-document ubiquitous files) |","url":"hs.spotlight.html#scope","kind":"property"},{"fullName":"hs.spotlight.attribute","description":"Common Spotlight metadata attribute key shortcuts. These are plain kMDItem* string values — using them is equivalent to typing the raw key name, but they provide autocomplete and avoid typos. | Key | Attribute | Description | |-----|-----------|-------------| | path | kMDItemPath | Absolute filesystem path | | displayName | kMDItemDisplayName | User-visible display name | | fsName | kMDItemFSName | Filename on disk | | contentType | kMDItemContentType | UTI content type | | contentTypeTree | kMDItemContentTypeTree | Full UTI conformance tree | | kind | kMDItemKind | Finder \"Kind\" string | | fileSize | kMDItemFSSize | File size in bytes | | creationDate | kMDItemFSCreationDate | Filesystem creation date | | modifiedDate | kMDItemFSContentChangeDate | Last content modification date | | lastUsedDate | kMDItemLastUsedDate | Last time the item was opened | | useCount | kMDItemUseCount | Number of times opened | | authors | kMDItemAuthors | Document authors | | title | kMDItemTitle | Document title | | comment | kMDItemComment | User comment | | keywords | kMDItemKeywords | Tags/keywords | | durationSeconds | kMDItemDurationSeconds | Media duration in seconds | | pixelWidth | kMDItemPixelWidth | Image/video width in pixels | | pixelHeight | kMDItemPixelHeight | Image/video height in pixels | | whereFroms | kMDItemWhereFroms | Download source URLs | | bundleIdentifier | kMDItemCFBundleIdentifier | App bundle identifier |","url":"hs.spotlight.html#attribute","kind":"property"},{"fullName":"hs.spotlight.create()","description":"Creates and returns a new, unconfigured Spotlight query. Configure it with setQuery(), setScopes(), and setCallback(), then call start(). The query is automatically stopped and released when the module shuts down.","url":"hs.spotlight.html#create","kind":"method"},{"fullName":"hs.spotlight.search(predicate, callback)","description":"Convenience helper that creates, configures, and starts a query in one call. Equivalent to create().setQuery(predicate).setCallback(callback).start(). Call q.stop() from inside callback (when event === 'didFinish') to end the search once you have what you need.","url":"hs.spotlight.html#search","kind":"method"},{"fullName":"hs.task","description":"Module for running external processes","url":"hs.task.html","kind":"module"},{"fullName":"hs.task.sequence","description":"Run multiple tasks in sequence. Swift-retained storage for the JS implementation.","url":"hs.task.html#sequence","kind":"property"},{"fullName":"hs.task.TaskBuilder","description":"TaskBuilder class. Swift-retained storage for the JS implementation.","url":"hs.task.html#TaskBuilder","kind":"property"},{"fullName":"hs.task.create(launchPath, arguments, completionCallback, environment, streamingCallback)","description":"Create a new task","url":"hs.task.html#create","kind":"method"},{"fullName":"hs.task.runAsync(launchPath, args, options, legacyStreamCallback)","description":"Create and run a task asynchronously","url":"hs.task.html#runAsync","kind":"method"},{"fullName":"hs.task.shell(command, options)","description":"Run a shell command asynchronously","url":"hs.task.html#shell","kind":"method"},{"fullName":"hs.task.parallel()","description":"Run multiple tasks in parallel","url":"hs.task.html#parallel","kind":"method"},{"fullName":"hs.task.builder(launchPath)","description":"Create a task builder for fluent API","url":"hs.task.html#builder","kind":"method"},{"fullName":"hs.timer","description":"Module for creating and managing timers","url":"hs.timer.html","kind":"module"},{"fullName":"hs.timer.create(interval, callback, continueOnError)","description":"Create a new timer","url":"hs.timer.html#create","kind":"method"},{"fullName":"hs.timer.doAfter(seconds, callback)","description":"Create and start a one-shot timer","url":"hs.timer.html#doAfter","kind":"method"},{"fullName":"hs.timer.doEvery(interval, callback)","description":"Create and start a repeating timer","url":"hs.timer.html#doEvery","kind":"method"},{"fullName":"hs.timer.doAt(time, repeatInterval, callback, continueOnError)","description":"Create and start a timer that fires at a specific time","url":"hs.timer.html#doAt","kind":"method"},{"fullName":"hs.timer.usleep(microseconds)","description":"Block execution for a specified number of microseconds (strongly discouraged)","url":"hs.timer.html#usleep","kind":"method"},{"fullName":"hs.timer.secondsSinceEpoch()","description":"Get the current time as seconds since the UNIX epoch with sub-second precision","url":"hs.timer.html#secondsSinceEpoch","kind":"method"},{"fullName":"hs.timer.absoluteTime()","description":"Get the number of nanoseconds since the system was booted (excluding sleep time)","url":"hs.timer.html#absoluteTime","kind":"method"},{"fullName":"hs.timer.localTime()","description":"Get the number of seconds since local midnight","url":"hs.timer.html#localTime","kind":"method"},{"fullName":"hs.timer.minutes(n)","description":"Converts minutes to seconds","url":"hs.timer.html#minutes","kind":"method"},{"fullName":"hs.timer.hours(n)","description":"Converts hours to seconds","url":"hs.timer.html#hours","kind":"method"},{"fullName":"hs.timer.days(n)","description":"Converts days to seconds","url":"hs.timer.html#days","kind":"method"},{"fullName":"hs.timer.weeks(n)","description":"Converts weeks to seconds","url":"hs.timer.html#weeks","kind":"method"},{"fullName":"hs.timer.doUntil(predicateFn, actionFn, checkInterval)","description":"Repeat a function/lambda until a given predicate function/lambda returns true","url":"hs.timer.html#doUntil","kind":"method"},{"fullName":"hs.timer.doWhile(predicateFn, actionFn, checkInterval)","description":"Repeat a function/lambda while a given predicate function/lambda returns true","url":"hs.timer.html#doWhile","kind":"method"},{"fullName":"hs.timer.waitUntil(predicateFn, actionFn, checkInterval)","description":"Wait to call a function/lambda until a given predicate function/lambda returns true","url":"hs.timer.html#waitUntil","kind":"method"},{"fullName":"hs.timer.waitWhile(predicateFn, actionFn, checkInterval)","description":"Wait to call a function/lambda until a given predicate function/lambda returns false","url":"hs.timer.html#waitWhile","kind":"method"},{"fullName":"hs.translation","description":"Translate text between languages using the macOS on-device Translation framework.","url":"hs.translation.html","kind":"module"},{"fullName":"hs.translation.supportedLanguages()","description":"All language codes supported by the on-device translation engine. Resolves to an array of BCP-47 identifiers (e.g. [\"ar\", \"de\", \"en\", \"es\", \"fr\"]). This covers every language the framework knows about, regardless of whether the packs are installed locally. Use status() to distinguish installed pairs from merely supported ones.","url":"hs.translation.html#supportedLanguages","kind":"method"},{"fullName":"hs.translation.status(sourceLanguage, targetLanguage)","description":"Check the installation status of a language pair.","url":"hs.translation.html#status","kind":"method"},{"fullName":"hs.translation.session(sourceLanguage, targetLanguage)","description":"Create a translation session for a language pair. Returns an HSTranslationSession, or null if the system is running macOS older than 26.0.","url":"hs.translation.html#session","kind":"method"},{"fullName":"hs.ui","description":"# hs.ui","url":"hs.ui.html","kind":"module"},{"fullName":"hs.ui.window(dict)","description":"Create a custom UI window Creates a borderless window that can contain custom UI elements built using a declarative, SwiftUI-like syntax with shapes, text, and layout containers.","url":"hs.ui.html#window","kind":"method"},{"fullName":"hs.ui.alert(message)","description":"Create a temporary on-screen alert Displays a temporary notification that automatically dismisses after the specified duration. Similar to the old hs.alert module but with more features.","url":"hs.ui.html#alert","kind":"method"},{"fullName":"hs.ui.dialog(message)","description":"Create a modal dialog with buttons Shows a blocking dialog with customizable message, informative text, and buttons. Use the callback to handle button presses.","url":"hs.ui.html#dialog","kind":"method"},{"fullName":"hs.ui.textPrompt(message)","description":"Create a text input prompt Shows a modal dialog with a text input field. The callback receives the button index and the entered text.","url":"hs.ui.html#textPrompt","kind":"method"},{"fullName":"hs.ui.string(initialValue)","description":"Create a reactive string for binding text element content to a dynamic value An HSString is a reactive value container. When passed to .text(), the canvas automatically re-renders whenever .set() is called from JavaScript.","url":"hs.ui.html#string","kind":"method"},{"fullName":"hs.ui.filePicker()","description":"Create a file or directory picker Shows a standard macOS file picker dialog. Can be configured to select files, directories, or both, with support for file type filtering and multiple selection.","url":"hs.ui.html#filePicker","kind":"method"},{"fullName":"hs.ui.webview()","description":"Create a web browser element for embedding in hs.ui.window (macOS 26+) Returns a UIWebView element that you configure and then embed in any hs.ui.window via .webview(element). The element fills the available space inside the window layout. Keep a reference to call navigation methods after the window is shown.","url":"hs.ui.html#webview","kind":"method"},{"fullName":"hs.urlevent","description":"Handle URL events received by Hammerspoon 2.","url":"hs.urlevent.html","kind":"module"},{"fullName":"hs.urlevent.httpCallback","description":"Callback invoked when Hammerspoon 2 receives an http:// or https:// URL. Fires only when Hammerspoon 2 is the system default handler for http/https. Assign null to remove the callback.","url":"hs.urlevent.html#httpCallback","kind":"property"},{"fullName":"hs.urlevent.mailtoCallback","description":"Callback invoked when Hammerspoon 2 receives a mailto: URL. Fires only when Hammerspoon 2 is the system default handler for mailto. Assign null to remove the callback.","url":"hs.urlevent.html#mailtoCallback","kind":"property"},{"fullName":"hs.urlevent.bind(eventName, callback)","description":"Register or remove a callback for a named hammerspoon2:// URL event. The URL format is hammerspoon2://eventName?key=value. The host component (eventName) selects the callback to invoke.","url":"hs.urlevent.html#bind","kind":"method"},{"fullName":"hs.urlevent.openURL(urlString)","description":"Open a URL using the system default application for its scheme.","url":"hs.urlevent.html#openURL","kind":"method"},{"fullName":"hs.urlevent.openURLWithBundle(urlString, bundleID)","description":"Open a URL with a specific application identified by bundle ID.","url":"hs.urlevent.html#openURLWithBundle","kind":"method"},{"fullName":"hs.urlevent.getDefaultHandler(scheme)","description":"Returns the bundle identifier of the default application for a URL scheme.","url":"hs.urlevent.html#getDefaultHandler","kind":"method"},{"fullName":"hs.urlevent.getAllHandlersForScheme(scheme)","description":"Returns all bundle identifiers capable of handling a URL scheme.","url":"hs.urlevent.html#getAllHandlersForScheme","kind":"method"},{"fullName":"hs.urlevent.setDefaultHandler(scheme, bundleID)","description":"Set the default application for a URL scheme. macOS may display a confirmation dialog for sensitive schemes such as http and https. For custom schemes (hammerspoon2) no dialog is shown.","url":"hs.urlevent.html#setDefaultHandler","kind":"method"},{"fullName":"hs.usb","description":"Module for monitoring USB device connections and disconnections","url":"hs.usb.html","kind":"module"},{"fullName":"hs.usb.attachedDevices()","description":"Returns all currently attached USB devices.","url":"hs.usb.html#attachedDevices","kind":"method"},{"fullName":"hs.usb.addWatcher(listener)","description":"Register a listener for USB device connection and disconnection events. The listener is called with two arguments: the event type string (\"added\" or \"removed\") and a device-info object with the same fields as attachedDevices().","url":"hs.usb.html#addWatcher","kind":"method"},{"fullName":"hs.usb.removeWatcher(listener)","description":"Remove a previously registered USB event listener.","url":"hs.usb.html#removeWatcher","kind":"method"},{"fullName":"hs.window","description":"Module for interacting with windows","url":"hs.window.html","kind":"module"},{"fullName":"hs.window.focusedWindow()","description":"Get the currently focused window","url":"hs.window.html#focusedWindow","kind":"method"},{"fullName":"hs.window.allWindows()","description":"Get all windows from all applications","url":"hs.window.html#allWindows","kind":"method"},{"fullName":"hs.window.visibleWindows()","description":"Get all visible (not minimized) windows","url":"hs.window.html#visibleWindows","kind":"method"},{"fullName":"hs.window.windowsForApp(app)","description":"Get windows for a specific application","url":"hs.window.html#windowsForApp","kind":"method"},{"fullName":"hs.window.windowsOnScreen(screenIndex)","description":"Get all windows on a specific screen","url":"hs.window.html#windowsOnScreen","kind":"method"},{"fullName":"hs.window.windowAtPoint(point)","description":"Get the window at a specific screen position","url":"hs.window.html#windowAtPoint","kind":"method"},{"fullName":"hs.window.orderedWindows()","description":"Get ordered windows (front to back)","url":"hs.window.html#orderedWindows","kind":"method"},{"fullName":"hs.window.findByTitle(title)","description":"Find windows by title Parameter title: The window title to search for. All windows with titles that include this string, will be matched","url":"hs.window.html#findByTitle","kind":"method"},{"fullName":"hs.window.currentWindows()","description":"Get all windows for the current application","url":"hs.window.html#currentWindows","kind":"method"},{"fullName":"hs.window.moveToLeftHalf(win)","description":"Move a window to left half of screen Parameter win: An HSWindow object","url":"hs.window.html#moveToLeftHalf","kind":"method"},{"fullName":"hs.window.moveToRightHalf(win)","description":"Move a window to right half of screen Parameter win: An HSWindow object","url":"hs.window.html#moveToRightHalf","kind":"method"},{"fullName":"hs.window.maximize(win)","description":"Maximize a window Parameter win: An HSWindow object","url":"hs.window.html#maximize","kind":"method"},{"fullName":"hs.window.cycleWindows()","description":"SKIP_DOCS","url":"hs.window.html#cycleWindows","kind":"method"},{"fullName":"HSApplication","description":"Object representing an application. You should not instantiate this directly in JavaScript, but rather, use the methods from hs.application which will return appropriate HSApplication objects.","url":"HSApplication.html","kind":"type"},{"fullName":"HSApplication.pid","description":"POSIX Process Identifier","url":"HSApplication.html#pid","kind":"property"},{"fullName":"HSApplication.bundleID","description":"Bundle Identifier (e.g. com.apple.Safari)","url":"HSApplication.html#bundleID","kind":"property"},{"fullName":"HSApplication.title","description":"The application's title","url":"HSApplication.html#title","kind":"property"},{"fullName":"HSApplication.bundlePath","description":"Location of the application on disk","url":"HSApplication.html#bundlePath","kind":"property"},{"fullName":"HSApplication.isHidden","description":"Is the application hidden","url":"HSApplication.html#isHidden","kind":"property"},{"fullName":"HSApplication.isActive","description":"Is the application focused","url":"HSApplication.html#isActive","kind":"property"},{"fullName":"HSApplication.mainWindow","description":"The main window of this application, or nil if there is no main window","url":"HSApplication.html#mainWindow","kind":"property"},{"fullName":"HSApplication.focusedWindow","description":"The focused window of this application, or nil if there is no focused window","url":"HSApplication.html#focusedWindow","kind":"property"},{"fullName":"HSApplication.allWindows","description":"All windows of this application","url":"HSApplication.html#allWindows","kind":"property"},{"fullName":"HSApplication.visibleWindows","description":"All visible (ie non-hidden) windows of this application","url":"HSApplication.html#visibleWindows","kind":"property"},{"fullName":"HSApplication.isRunning","description":"Whether the application process is still running","url":"HSApplication.html#isRunning","kind":"property"},{"fullName":"HSApplication.kind","description":"The kind of application: \"standard\" (regular dock app), \"accessory\" (no dock), or \"background\" (agent)","url":"HSApplication.html#kind","kind":"property"},{"fullName":"HSApplication.kill()","description":"Terminate the application","url":"HSApplication.html#kill","kind":"method"},{"fullName":"HSApplication.kill9()","description":"Force-terminate the application","url":"HSApplication.html#kill9","kind":"method"},{"fullName":"HSApplication.axElement()","description":"The application's HSAXElement object, for use with the hs.ax APIs","url":"HSApplication.html#axElement","kind":"method"},{"fullName":"HSApplication.activate(allWindows)","description":"Bring this application to the foreground","url":"HSApplication.html#activate","kind":"method"},{"fullName":"HSApplication.hide()","description":"Hide this application and all its windows","url":"HSApplication.html#hide","kind":"method"},{"fullName":"HSApplication.unhide()","description":"Unhide this application","url":"HSApplication.html#unhide","kind":"method"},{"fullName":"HSApplication.getMenuItems()","description":"Get the full menu structure of this application","url":"HSApplication.html#getMenuItems","kind":"method"},{"fullName":"HSApplication.findMenuItemByName(name)","description":"Find a menu item by searching all menus for a matching title (case-insensitive)","url":"HSApplication.html#findMenuItemByName","kind":"method"},{"fullName":"HSApplication.findMenuItemByPath(path)","description":"Find a menu item by following a hierarchical path of titles","url":"HSApplication.html#findMenuItemByPath","kind":"method"},{"fullName":"HSApplication.selectMenuItemByName(name)","description":"Click a menu item found by searching all menus for a matching title (case-insensitive)","url":"HSApplication.html#selectMenuItemByName","kind":"method"},{"fullName":"HSApplication.selectMenuItemByPath(path)","description":"Click a menu item found by following a hierarchical path of titles","url":"HSApplication.html#selectMenuItemByPath","kind":"method"},{"fullName":"HSApplication.findWindow(pattern)","description":"Find windows whose title contains the given string (case-insensitive)","url":"HSApplication.html#findWindow","kind":"method"},{"fullName":"HSApplication.getWindow(title)","description":"Get the first window with exactly the given title","url":"HSApplication.html#getWindow","kind":"method"},{"fullName":"HSAudioDevice","description":"An audio device attached to the system. Obtain instances via `hs.audiodevice module methods — do not instantiate directly. ## Getting and setting volume `javascript const dev = hs.audiodevice.defaultOutputDevice(); if (dev) { console.log(dev.volume); // 0.0 – 1.0, or null dev.volume = 0.5; } ` ## Watching for changes `javascript const dev = hs.audiodevice.defaultOutputDevice(); if (dev) { var fn = function(event) { console.log(\"Device event:\", event); }; dev.addWatcher(fn); // later… dev.removeWatcher(fn); } ``","url":"HSAudioDevice.html","kind":"type"},{"fullName":"HSAudioDevice.id","description":"The CoreAudio object ID of this device.","url":"HSAudioDevice.html#id","kind":"property"},{"fullName":"HSAudioDevice.name","description":"The human-readable name of this device (e.g. \"Built-in Output\").","url":"HSAudioDevice.html#name","kind":"property"},{"fullName":"HSAudioDevice.uid","description":"The persistent unique identifier for this device.","url":"HSAudioDevice.html#uid","kind":"property"},{"fullName":"HSAudioDevice.isOutput","description":"Whether this device has output streams (can play audio).","url":"HSAudioDevice.html#isOutput","kind":"property"},{"fullName":"HSAudioDevice.isInput","description":"Whether this device has input streams (can record audio).","url":"HSAudioDevice.html#isInput","kind":"property"},{"fullName":"HSAudioDevice.transportType","description":"The transport mechanism: \"built-in\", \"usb\", \"bluetooth\", \"bluetooth-le\", \"hdmi\", \"display-port\", \"firewire\", \"airplay\", \"avb\", \"thunderbolt\", \"virtual\", \"aggregate\", \"pci\", or \"unknown\".","url":"HSAudioDevice.html#transportType","kind":"property"},{"fullName":"HSAudioDevice.outputChannels","description":"Number of output channels, or 0 if the device has no output.","url":"HSAudioDevice.html#outputChannels","kind":"property"},{"fullName":"HSAudioDevice.inputChannels","description":"Number of input channels, or 0 if the device has no input.","url":"HSAudioDevice.html#inputChannels","kind":"property"},{"fullName":"HSAudioDevice.volume","description":"Output volume scalar in the range 0.0–1.0, or null if the device has no controllable output volume. Setting null is a no-op.","url":"HSAudioDevice.html#volume","kind":"property"},{"fullName":"HSAudioDevice.muted","description":"Whether output is muted. Always false if the device has no mutable output.","url":"HSAudioDevice.html#muted","kind":"property"},{"fullName":"HSAudioDevice.balance","description":"Output stereo balance in the range 0.0 (full left)–1.0 (full right), or null if balance control is not available.","url":"HSAudioDevice.html#balance","kind":"property"},{"fullName":"HSAudioDevice.inputVolume","description":"Input (microphone) volume scalar in the range 0.0–1.0, or null if the device has no controllable input volume.","url":"HSAudioDevice.html#inputVolume","kind":"property"},{"fullName":"HSAudioDevice.inputMuted","description":"Whether input is muted. Always false if the device has no mutable input.","url":"HSAudioDevice.html#inputMuted","kind":"property"},{"fullName":"HSAudioDevice.sampleRate","description":"The current nominal sample rate in Hz (e.g. 44100), or null if unknown.","url":"HSAudioDevice.html#sampleRate","kind":"property"},{"fullName":"HSAudioDevice.availableSampleRates","description":"All sample rates (in Hz) that this device supports. For devices that support a range, both the minimum and maximum are included.","url":"HSAudioDevice.html#availableSampleRates","kind":"property"},{"fullName":"HSAudioDevice.currentOutputDataSource()","description":"The current output data source as { id, name }, or null if unavailable.","url":"HSAudioDevice.html#currentOutputDataSource","kind":"method"},{"fullName":"HSAudioDevice.currentInputDataSource()","description":"The current input data source as { id, name }, or null if unavailable.","url":"HSAudioDevice.html#currentInputDataSource","kind":"method"},{"fullName":"HSAudioDevice.outputDataSources()","description":"All available output data sources as an array of { id, name } objects.","url":"HSAudioDevice.html#outputDataSources","kind":"method"},{"fullName":"HSAudioDevice.inputDataSources()","description":"All available input data sources as an array of { id, name } objects.","url":"HSAudioDevice.html#inputDataSources","kind":"method"},{"fullName":"HSAudioDevice.setCurrentOutputDataSource(sourceID)","description":"Select an output data source by its numeric ID.","url":"HSAudioDevice.html#setCurrentOutputDataSource","kind":"method"},{"fullName":"HSAudioDevice.setCurrentInputDataSource(sourceID)","description":"Select an input data source by its numeric ID.","url":"HSAudioDevice.html#setCurrentInputDataSource","kind":"method"},{"fullName":"HSAudioDevice.setDefaultOutputDevice()","description":"Make this device the system default output device.","url":"HSAudioDevice.html#setDefaultOutputDevice","kind":"method"},{"fullName":"HSAudioDevice.setDefaultInputDevice()","description":"Make this device the system default input device.","url":"HSAudioDevice.html#setDefaultInputDevice","kind":"method"},{"fullName":"HSAudioDevice.setDefaultEffectDevice()","description":"Make this device the system alert sound (effect) device.","url":"HSAudioDevice.html#setDefaultEffectDevice","kind":"method"},{"fullName":"HSAudioDevice.addWatcher(listener)","description":"Register a listener for a per-device property-change event.","url":"HSAudioDevice.html#addWatcher","kind":"method"},{"fullName":"HSAudioDevice.removeWatcher(listener)","description":"Remove a previously registered per-device listener.","url":"HSAudioDevice.html#removeWatcher","kind":"method"},{"fullName":"HSAXElement","description":"Object representing an Accessibility element. You should not instantiate this directly, but rather, use the hs.ax methods to create these as required.","url":"HSAXElement.html","kind":"type"},{"fullName":"HSAXElement.role","description":"The element's role (e.g., \"AXWindow\", \"AXButton\")","url":"HSAXElement.html#role","kind":"property"},{"fullName":"HSAXElement.subrole","description":"The element's subrole","url":"HSAXElement.html#subrole","kind":"property"},{"fullName":"HSAXElement.title","description":"The element's title","url":"HSAXElement.html#title","kind":"property"},{"fullName":"HSAXElement.value","description":"The element's value","url":"HSAXElement.html#value","kind":"property"},{"fullName":"HSAXElement.elementDescription","description":"The element's description","url":"HSAXElement.html#elementDescription","kind":"property"},{"fullName":"HSAXElement.isEnabled","description":"Whether the element is enabled","url":"HSAXElement.html#isEnabled","kind":"property"},{"fullName":"HSAXElement.isFocused","description":"Whether the element is focused","url":"HSAXElement.html#isFocused","kind":"property"},{"fullName":"HSAXElement.position","description":"The element's position on screen","url":"HSAXElement.html#position","kind":"property"},{"fullName":"HSAXElement.size","description":"The element's size","url":"HSAXElement.html#size","kind":"property"},{"fullName":"HSAXElement.frame","description":"The element's frame (position and size combined)","url":"HSAXElement.html#frame","kind":"property"},{"fullName":"HSAXElement.parent","description":"The element's parent","url":"HSAXElement.html#parent","kind":"property"},{"fullName":"HSAXElement.pid","description":"Get the process ID of the application that owns this element","url":"HSAXElement.html#pid","kind":"property"},{"fullName":"HSAXElement.children()","description":"The element's children","url":"HSAXElement.html#children","kind":"method"},{"fullName":"HSAXElement.childAtIndex(index)","description":"Get a specific child by index","url":"HSAXElement.html#childAtIndex","kind":"method"},{"fullName":"HSAXElement.attributeNames()","description":"Get all available attribute names","url":"HSAXElement.html#attributeNames","kind":"method"},{"fullName":"HSAXElement.attributeValue(attribute)","description":"Get the value of a specific attribute","url":"HSAXElement.html#attributeValue","kind":"method"},{"fullName":"HSAXElement.setAttributeValue(attribute, value)","description":"Set the value of a specific attribute","url":"HSAXElement.html#setAttributeValue","kind":"method"},{"fullName":"HSAXElement.isAttributeSettable(attribute)","description":"Check if an attribute is settable","url":"HSAXElement.html#isAttributeSettable","kind":"method"},{"fullName":"HSAXElement.actionNames()","description":"Get all available action names","url":"HSAXElement.html#actionNames","kind":"method"},{"fullName":"HSAXElement.performAction(action)","description":"Perform a specific action","url":"HSAXElement.html#performAction","kind":"method"},{"fullName":"HSBonjourSearch","description":"Discovers Bonjour services and domains advertised on the local network. Create via hs.bonjour.newSearch(), then call one of the find… methods. Each search type uses its own underlying NetServiceBrowser, so service and domain searches can run concurrently. Restarting any single search type stops only that browser before beginning the new one. ## Service search callback events | Event | Data | Description | |-------|------|-------------| | \"serviceFound\" | HSBonjourService | A matching service appeared | | \"serviceRemoved\" | HSBonjourService | A previously found service disappeared | | \"error\" | error string | The search failed | ## Domain search callback events | Event | Data | Description | |-------|------|-------------| | \"domainFound\" | domain string | A domain was discovered | | \"domainRemoved\" | domain string | A domain disappeared | | \"error\" | error string | The search failed |","url":"HSBonjourSearch.html","kind":"type"},{"fullName":"HSBonjourSearch.identifier","description":"A unique identifier for this search object.","url":"HSBonjourSearch.html#identifier","kind":"property"},{"fullName":"HSBonjourSearch.includesPeerToPeer","description":"Whether to search over peer-to-peer Bluetooth/Wi-Fi in addition to standard network interfaces. Defaults to false.","url":"HSBonjourSearch.html#includesPeerToPeer","kind":"property"},{"fullName":"HSBonjourSearch.findServices(type, domain, callback)","description":"Searches for services of the given type in the given domain. If a service search is already active it is stopped before starting the new one. Domain searches are unaffected. The callback receives (event, service, moreComing) — see the type documentation for the complete event table.","url":"HSBonjourSearch.html#findServices","kind":"method"},{"fullName":"HSBonjourSearch.findBrowsableDomains(callback)","description":"Searches for domains visible to this machine (browsable domains). If a browsable-domain search is already active it is stopped before starting the new one. Service and registration-domain searches are unaffected. The callback receives (event, domain, moreComing).","url":"HSBonjourSearch.html#findBrowsableDomains","kind":"method"},{"fullName":"HSBonjourSearch.findRegistrationDomains(callback)","description":"Searches for domains on which this machine can register services. If a registration-domain search is already active it is stopped before starting the new one. Service and browsable-domain searches are unaffected. The callback receives (event, domain, moreComing).","url":"HSBonjourSearch.html#findRegistrationDomains","kind":"method"},{"fullName":"HSBonjourSearch.stop()","description":"Stops all active searches. Safe to call when no search is active.","url":"HSBonjourSearch.html#stop","kind":"method"},{"fullName":"HSBonjourService","description":"A discovered Bonjour service record. Call resolve() to look up its hostname, port, and addresses. Instances are delivered by an HSBonjourSearch callback. Call resolve() to discover their hostname, port, and addresses, and optionally monitor() to watch for TXT record changes. ## Callback events | Method | Event | Extra data | |--------|-------|------------| | resolve() | \"resolved\" | _(none)_ | | resolve() | \"stopped\" | _(none)_ | | resolve() | \"error\" | error message string | | monitor() | \"txtRecord\" | updated TXT record dict |","url":"HSBonjourService.html","kind":"type"},{"fullName":"HSBonjourService.identifier","description":"A unique identifier assigned to this service object.","url":"HSBonjourService.html#identifier","kind":"property"},{"fullName":"HSBonjourService.name","description":"The service name (e.g. \"My Web Server\").","url":"HSBonjourService.html#name","kind":"property"},{"fullName":"HSBonjourService.type","description":"The service type string (e.g. \"_http._tcp.\").","url":"HSBonjourService.html#type","kind":"property"},{"fullName":"HSBonjourService.domain","description":"The mDNS domain (almost always \"local.\").","url":"HSBonjourService.html#domain","kind":"property"},{"fullName":"HSBonjourService.hostname","description":"The resolved hostname, or null before resolve() completes.","url":"HSBonjourService.html#hostname","kind":"property"},{"fullName":"HSBonjourService.port","description":"The service port. -1 until resolve() completes.","url":"HSBonjourService.html#port","kind":"property"},{"fullName":"HSBonjourService.addresses","description":"IP address strings (IPv4 and/or IPv6) populated after resolve() completes.","url":"HSBonjourService.html#addresses","kind":"property"},{"fullName":"HSBonjourService.txtRecord","description":"The TXT record as a {key: value} object, or null if none is available. Populated after resolve() completes or when updated via monitor().","url":"HSBonjourService.html#txtRecord","kind":"property"},{"fullName":"HSBonjourService.includesPeerToPeer","description":"Whether peer-to-peer Bluetooth/Wi-Fi is included in resolution.","url":"HSBonjourService.html#includesPeerToPeer","kind":"property"},{"fullName":"HSBonjourService.resolve(timeout, callback)","description":"Resolves the hostname, port, addresses, and TXT record of this service.","url":"HSBonjourService.html#resolve","kind":"method"},{"fullName":"HSBonjourService.monitor(callback)","description":"Starts monitoring the TXT record for changes. The callback fires whenever the TXT record is updated. Call stopMonitoring() to unsubscribe.","url":"HSBonjourService.html#monitor","kind":"method"},{"fullName":"HSBonjourService.stop()","description":"Stops any active resolution.","url":"HSBonjourService.html#stop","kind":"method"},{"fullName":"HSBonjourService.stopMonitoring()","description":"Stops TXT record monitoring started by monitor().","url":"HSBonjourService.html#stopMonitoring","kind":"method"},{"fullName":"HSCamera","description":"A camera device attached to the system. Obtain instances via the `hs.camera module — do not instantiate directly. ## Reading camera properties `javascript const cam = hs.camera.all()[0] console.log(cam.name + \" uid=\" + cam.uid + \" inUse=\" + cam.isInUse) ` ## Watching for in-use state changes `javascript const cam = hs.camera.all()[0] const fn = (isInUse) => { console.log(cam.name + \" is now \" + (isInUse ? \"in use\" : \"not in use\")) } cam.addWatcher(fn) // later… cam.removeWatcher(fn) ` ## Capturing a still image `javascript const cam = hs.camera.all()[0] cam.captureImage() .then(img => img.saveToFile(\"/tmp/shot.png\")) .catch(err => console.error(\"Capture failed: \" + err)) ``","url":"HSCamera.html","kind":"type"},{"fullName":"HSCamera.typeName","description":"The type name for JavaScript introspection. Always \"HSCamera\".","url":"HSCamera.html#typeName","kind":"property"},{"fullName":"HSCamera.uid","description":"The persistent unique identifier for this camera.","url":"HSCamera.html#uid","kind":"property"},{"fullName":"HSCamera.name","description":"The human-readable name of this camera (e.g. \"FaceTime HD Camera\").","url":"HSCamera.html#name","kind":"property"},{"fullName":"HSCamera.isInUse","description":"Whether this camera is currently being used by any application. Queries the underlying CoreMediaIO device state each time it is read.","url":"HSCamera.html#isInUse","kind":"property"},{"fullName":"HSCamera.addWatcher(listener)","description":"Register a listener that fires whenever this camera's in-use state changes. The listener receives one argument: a boolean that is true when the camera starts being used and false when it is released.","url":"HSCamera.html#addWatcher","kind":"method"},{"fullName":"HSCamera.removeWatcher(listener)","description":"Remove a previously registered per-camera in-use listener.","url":"HSCamera.html#removeWatcher","kind":"method"},{"fullName":"HSCamera.captureImage()","description":"Capture a still image from this camera. Camera permission must be granted via hs.permissions.requestCamera() before calling this method. The returned HSImage can be saved, displayed in a UI element, or passed to other image-processing APIs.","url":"HSCamera.html#captureImage","kind":"method"},{"fullName":"HSChooser","description":"A keyboard-driven floating chooser panel. Create via hs.chooser.create(). Configure choices, set callbacks, then call .show(). ## Choice format Each choice is a plain object with required text and optional subText, image, valid, and contextMenu fields. All other fields are passed through to the onSelect callback unchanged. The contextMenu array defines per-row right-click menu entries. Each entry is either ``javascript { text: \"Open Safari\", subText: \"com.apple.Safari\", image: HSImage.fromAppBundle(\"com.apple.Safari\"), valid: true, myData: 42, contextMenu: [ { title: \"Open\", action: () => hs.urlevent.openURL(\"https://apple.com\") }, { type: \"divider\" }, { title: \"Copy bundle ID\", action: () => hs.pasteboard.writeString(\"com.apple.Safari\") } ] } `` ## Keyboard shortcuts","url":"HSChooser.html","kind":"type"},{"fullName":"HSChooser.typeName","description":"Read-only type identifier.","url":"HSChooser.html#typeName","kind":"property"},{"fullName":"HSChooser.identifier","description":"Stable UUID string for this chooser instance.","url":"HSChooser.html#identifier","kind":"property"},{"fullName":"HSChooser.query","description":"The current text in the search field. Setting this from JS updates the display but does not invoke the onQueryChange callback.","url":"HSChooser.html#query","kind":"property"},{"fullName":"HSChooser.placeholder","description":"Placeholder text shown in the empty search field (default: \"Search...\").","url":"HSChooser.html#placeholder","kind":"property"},{"fullName":"HSChooser.searchSubText","description":"Whether searches match against subText in addition to text (default: false). Only applies when a static choices array is provided.","url":"HSChooser.html#searchSubText","kind":"property"},{"fullName":"HSChooser.enableDefaultForQuery","description":"When true and the query is non-empty but there are no matching choices, onSelect is called with { text: } instead of null (default: false).","url":"HSChooser.html#enableDefaultForQuery","kind":"property"},{"fullName":"HSChooser.selectedRow","description":"The zero-based index of the currently highlighted row (-1 when empty).","url":"HSChooser.html#selectedRow","kind":"property"},{"fullName":"HSChooser.width","description":"Width of the chooser as a fraction of the screen width (default: 0.5 = 50 %).","url":"HSChooser.html#width","kind":"property"},{"fullName":"HSChooser.visibleRows","description":"Maximum number of rows visible at once without scrolling (default: 10).","url":"HSChooser.html#visibleRows","kind":"property"},{"fullName":"HSChooser.isVisible","description":"true if the chooser panel is currently on screen.","url":"HSChooser.html#isVisible","kind":"property"},{"fullName":"HSChooser.onSelect","description":"Called when the user confirms a selection, or null to remove the handler. The argument is the chosen row object (the original dict you passed to setChoices, with text, subText, image, valid, and any custom fields intact). The argument is null when dismissed (Escape).","url":"HSChooser.html#onSelect","kind":"property"},{"fullName":"HSChooser.onQueryChange","description":"Called on every keystroke with the new query string, or null to remove the handler. Use this to debounce expensive searches or trigger async data fetching.","url":"HSChooser.html#onQueryChange","kind":"property"},{"fullName":"HSChooser.onShow","description":"Called after the panel becomes visible, or null to remove the handler.","url":"HSChooser.html#onShow","kind":"property"},{"fullName":"HSChooser.onHide","description":"Called after the panel is hidden (for any reason: selection, Escape, or hide()), or null to remove the handler.","url":"HSChooser.html#onHide","kind":"property"},{"fullName":"HSChooser.onInvalid","description":"Called when the user activates a row whose valid field is false, or null to remove the handler. The chooser stays open; the argument is the row dict (same shape as onSelect). If unset, activating an invalid row is silently ignored.","url":"HSChooser.html#onInvalid","kind":"property"},{"fullName":"HSChooser.setChoices(choices)","description":"on show. The function is responsible for filtering; the chooser displays all items it returns.","url":"HSChooser.html#setChoices","kind":"method"},{"fullName":"HSChooser.refreshChoices()","description":"Re-apply filtering (static choices) or re-invoke the choices function (dynamic). Call after updating an external data source in an async onQueryChange handler.","url":"HSChooser.html#refreshChoices","kind":"method"},{"fullName":"HSChooser.show()","description":"Show the chooser.","url":"HSChooser.html#show","kind":"method"},{"fullName":"HSChooser.hide()","description":"Hide the chooser without making a selection. Restores focus to the previously active window.","url":"HSChooser.html#hide","kind":"method"},{"fullName":"HSChooser.select(row)","description":"Programmatically confirm a selection. Omit row to confirm the currently highlighted row. Fires onSelect (or onInvalid for rows with valid: false) and hides the chooser.","url":"HSChooser.html#select","kind":"method"},{"fullName":"HSChooser.selectedRowContents(row)","description":"Returns the dict for the highlighted row, or for a specific row by index. Returns null if the index is out of range or no choices are set.","url":"HSChooser.html#selectedRowContents","kind":"method"},{"fullName":"HSEventTap","description":"An event tap watcher that intercepts input events from the system. Obtain instances via hs.eventtap.addWatcher() — do not instantiate directly. ## Monitoring keyboard events ``js const tap = hs.eventtap.addWatcher([hs.eventtap.eventTypes.keyDown], (event) => { console.log(\"Key pressed: \" + event.keyCode) }) ``","url":"HSEventTap.html","kind":"type"},{"fullName":"HSEventTap.identifier","description":"A unique identifier for this tap","url":"HSEventTap.html#identifier","kind":"property"},{"fullName":"HSEventTap.listenOnly","description":"Whether this tap was created as listen-only (events are observed but never modified or suppressed)","url":"HSEventTap.html#listenOnly","kind":"property"},{"fullName":"HSEventTap.start()","description":"Start receiving events. Requires Accessibility permission.","url":"HSEventTap.html#start","kind":"method"},{"fullName":"HSEventTap.stop()","description":"Stop receiving events","url":"HSEventTap.html#stop","kind":"method"},{"fullName":"HSEventTap.setCallback(callback)","description":"Replace the callback function","url":"HSEventTap.html#setCallback","kind":"method"},{"fullName":"HSEventTap.isEnabled()","description":"Whether this tap is currently active","url":"HSEventTap.html#isEnabled","kind":"method"},{"fullName":"HSEventTap.isCreated()","description":"Whether this tap has been registered with macOS","url":"HSEventTap.html#isCreated","kind":"method"},{"fullName":"HSEventTapEvent","description":"An input event captured or constructed by hs.eventtap. Objects of this type are passed to event tap callbacks and can also be created directly via the factory methods on hs.eventtap. Properties can be inspected and modified before the event is passed through or posted back to the system.","url":"HSEventTapEvent.html","kind":"type"},{"fullName":"HSEventTapEvent.typeName","description":"Type name for introspection","url":"HSEventTapEvent.html#typeName","kind":"property"},{"fullName":"HSEventTapEvent.type","description":"The numeric event type, matching a value in hs.eventtap.eventTypes","url":"HSEventTapEvent.html#type","kind":"property"},{"fullName":"HSEventTapEvent.keyCode","description":"The virtual key code for keyboard events (get/set)","url":"HSEventTapEvent.html#keyCode","kind":"property"},{"fullName":"HSEventTapEvent.rawFlags","description":"The raw modifier flags bitmask (get/set). Use values from hs.eventtap.modifierFlags.","url":"HSEventTapEvent.html#rawFlags","kind":"property"},{"fullName":"HSEventTapEvent.flags","description":"An array of active modifier key names (e.g. [\"cmd\", \"shift\"]). When a device-specific modifier is detected, both the generic and side-specific names are included — e.g. pressing the left Command key yields [\"cmd\", \"leftCmd\"].","url":"HSEventTapEvent.html#flags","kind":"property"},{"fullName":"HSEventTapEvent.location","description":"The event's screen position as {x, y} in Hammerspoon screen coordinates (top-left origin of primary display, y increases downward, matching hs.screen).","url":"HSEventTapEvent.html#location","kind":"property"},{"fullName":"HSEventTapEvent.buttonNumber","description":"The mouse button number for mouse events (0=left, 1=right, 2=middle)","url":"HSEventTapEvent.html#buttonNumber","kind":"property"},{"fullName":"HSEventTapEvent.scrollingDeltaX","description":"The horizontal scroll delta for scroll wheel events","url":"HSEventTapEvent.html#scrollingDeltaX","kind":"property"},{"fullName":"HSEventTapEvent.scrollingDeltaY","description":"The vertical scroll delta for scroll wheel events","url":"HSEventTapEvent.html#scrollingDeltaY","kind":"property"},{"fullName":"HSEventTapEvent.characters","description":"The Unicode characters produced by this keyboard event, or null for non-keyboard events","url":"HSEventTapEvent.html#characters","kind":"property"},{"fullName":"HSEventTapEvent.duplicate()","description":"Create an independent copy of this event","url":"HSEventTapEvent.html#duplicate","kind":"method"},{"fullName":"HSEventTapEvent.post(app)","description":"Post this event to the HID event stream, optionally targeting a specific application. When app is omitted or null, the event is posted to the global HID stream and delivered by the OS as if a real input device generated it. When an application is provided, the event is delivered directly to that process by PID.","url":"HSEventTapEvent.html#post","kind":"method"},{"fullName":"HSEventTapHotkey","description":"A keyboard shortcut binding backed by an event tap. Supports fn modifier and left/right modifier key distinction. Obtain instances via hs.eventtap.bindHotkey() — do not instantiate directly.","url":"HSEventTapHotkey.html","kind":"type"},{"fullName":"HSEventTapHotkey.callbackPressed","description":"The callback function to be called when the hotkey is pressed, or null to remove it","url":"HSEventTapHotkey.html#callbackPressed","kind":"property"},{"fullName":"HSEventTapHotkey.callbackReleased","description":"The callback function to be called when the hotkey is released, or null to remove it","url":"HSEventTapHotkey.html#callbackReleased","kind":"property"},{"fullName":"HSEventTapHotkey.enable()","description":"Enable the hotkey","url":"HSEventTapHotkey.html#enable","kind":"method"},{"fullName":"HSEventTapHotkey.disable()","description":"Disable the hotkey","url":"HSEventTapHotkey.html#disable","kind":"method"},{"fullName":"HSEventTapHotkey.isEnabled()","description":"Check if the hotkey is currently enabled","url":"HSEventTapHotkey.html#isEnabled","kind":"method"},{"fullName":"HSVolumeWatcher","description":"A volume event watcher that monitors filesystem mount/unmount/rename events. Create via hs.fs.addVolumeWatcher(). Set a callback with setCallback(), then call start() to begin receiving events. | Event | Info keys | |-------|-----------| | \"didMount\" | path: string | | \"didUnmount\" | path: string | | \"willUnmount\" | path: string | | \"didRename\" | path: string, name: string, oldPath?: string, oldName?: string |","url":"HSVolumeWatcher.html","kind":"type"},{"fullName":"HSVolumeWatcher.identifier","description":"The unique identifier assigned to this watcher.","url":"HSVolumeWatcher.html#identifier","kind":"property"},{"fullName":"HSVolumeWatcher.start()","description":"Starts monitoring volume events.","url":"HSVolumeWatcher.html#start","kind":"method"},{"fullName":"HSVolumeWatcher.stop()","description":"Stops monitoring volume events.","url":"HSVolumeWatcher.html#stop","kind":"method"},{"fullName":"HSVolumeWatcher.setCallback(fn)","description":"Sets the callback function invoked when volume events occur.","url":"HSVolumeWatcher.html#setCallback","kind":"method"},{"fullName":"HSVolumeWatcher.destroy()","description":"Stops the watcher and releases all resources. Called automatically during shutdown.","url":"HSVolumeWatcher.html#destroy","kind":"method"},{"fullName":"HSHotkey","description":"Object representing a system-wide hotkey. You should not create these objects directly, but rather, use the methods in hs.hotkey to instantiate these.","url":"HSHotkey.html","kind":"type"},{"fullName":"HSHotkey.callbackPressed","description":"The callback function to be called when the hotkey is pressed, or null to remove it","url":"HSHotkey.html#callbackPressed","kind":"property"},{"fullName":"HSHotkey.callbackReleased","description":"The callback function to be called when the hotkey is released, or null to remove it","url":"HSHotkey.html#callbackReleased","kind":"property"},{"fullName":"HSHotkey.enable()","description":"Enable the hotkey","url":"HSHotkey.html#enable","kind":"method"},{"fullName":"HSHotkey.disable()","description":"Disable the hotkey","url":"HSHotkey.html#disable","kind":"method"},{"fullName":"HSHotkey.isEnabled()","description":"Check if the hotkey is currently enabled","url":"HSHotkey.html#isEnabled","kind":"method"},{"fullName":"HSHotkey.destroy()","description":"Disable and permanently remove this hotkey, releasing all associated resources","url":"HSHotkey.html#destroy","kind":"method"},{"fullName":"HSWebSocket","description":"A WebSocket client connection created by hs.http.openWebSocket(). The connection opens immediately when returned. Use the chainable setter methods to register event callbacks, then call send() to transmit messages. Do not instantiate HSWebSocket directly — use hs.http.openWebSocket().","url":"HSWebSocket.html","kind":"type"},{"fullName":"HSWebSocket.identifier","description":"A unique identifier for this connection (UUID string).","url":"HSWebSocket.html#identifier","kind":"property"},{"fullName":"HSWebSocket.readyState","description":"The current connection state.","url":"HSWebSocket.html#readyState","kind":"property"},{"fullName":"HSWebSocket.setOpenCallback(callback)","description":"Set the callback invoked when the connection is established.","url":"HSWebSocket.html#setOpenCallback","kind":"method"},{"fullName":"HSWebSocket.setMessageCallback(callback)","description":"Set the callback invoked when a text message is received from the server.","url":"HSWebSocket.html#setMessageCallback","kind":"method"},{"fullName":"HSWebSocket.setCloseCallback(callback)","description":"Set the callback invoked when the connection is closed by the remote end.","url":"HSWebSocket.html#setCloseCallback","kind":"method"},{"fullName":"HSWebSocket.setErrorCallback(callback)","description":"Set the callback invoked when a connection or protocol error occurs.","url":"HSWebSocket.html#setErrorCallback","kind":"method"},{"fullName":"HSWebSocket.send(message)","description":"Send a text message to the server. The connection must be open (readyState === 1).","url":"HSWebSocket.html#send","kind":"method"},{"fullName":"HSWebSocket.close()","description":"Close the WebSocket connection with a normal closure code (1000). If a close callback is registered, it is invoked synchronously.","url":"HSWebSocket.html#close","kind":"method"},{"fullName":"HSWebSocket.destroy()","description":"Destroy this WebSocket, releasing all resources without invoking callbacks. Called automatically by hs.http.shutdown(). After destroy(), do not use this object.","url":"HSWebSocket.html#destroy","kind":"method"},{"fullName":"HSHTTPServer","description":"An HTTP server instance created by hs.httpserver.create(). Configure with chainable setter methods, then call start() to begin accepting connections. The server supports synchronous and async (Promise-returning) request callbacks, optional static file serving, HTTP Basic authentication, Bonjour advertisement, and TLS via PKCS#12. Do not instantiate HSHTTPServer directly — use hs.httpserver.create().","url":"HSHTTPServer.html","kind":"type"},{"fullName":"HSHTTPServer.identifier","description":"A unique identifier for this server instance (UUID string).","url":"HSHTTPServer.html#identifier","kind":"property"},{"fullName":"HSHTTPServer.setPort(port)","description":"Set the TCP port to listen on. Must be called before start(). Pass 0 to let the OS assign an available port (use getPort() after start() to discover it).","url":"HSHTTPServer.html#setPort","kind":"method"},{"fullName":"HSHTTPServer.setInterface(iface)","description":"Set the network interface to listen on. Pass null to listen on all interfaces (the default). Pass \"localhost\" or \"loopback\" to restrict to the loopback interface only.","url":"HSHTTPServer.html#setInterface","kind":"method"},{"fullName":"HSHTTPServer.setPassword(password)","description":"Set a password required for Basic authentication. When set, every request must supply an Authorization: Basic header with any username and the configured password. Pass null to disable authentication.","url":"HSHTTPServer.html#setPassword","kind":"method"},{"fullName":"HSHTTPServer.setMaxBodySize(size)","description":"Set the maximum allowed incoming request body size in bytes. Requests with a body exceeding this limit receive a 413 response. Defaults to 10 MB.","url":"HSHTTPServer.html#setMaxBodySize","kind":"method"},{"fullName":"HSHTTPServer.setName(name)","description":"Set the Bonjour service name advertised on the local network. Only used when Bonjour is enabled via setBonjour(true).","url":"HSHTTPServer.html#setName","kind":"method"},{"fullName":"HSHTTPServer.setBonjour(enable)","description":"Enable or disable Bonjour advertisement of this server on the local network.","url":"HSHTTPServer.html#setBonjour","kind":"method"},{"fullName":"HSHTTPServer.setCallback(callback)","description":"Set the request handler callback. If the callback returns null or undefined, the server falls through to static file serving (if a document root is set), or responds with 404.","url":"HSHTTPServer.html#setCallback","kind":"method"},{"fullName":"HSHTTPServer.setDocumentRoot(path)","description":"Set the filesystem path to serve static files from. When a document root is set, requests not handled by the callback are served as static files from this directory. Pass null to disable static file serving.","url":"HSHTTPServer.html#setDocumentRoot","kind":"method"},{"fullName":"HSHTTPServer.setDirectoryIndex(files)","description":"Set the list of index filenames checked when a directory is requested. Defaults to [\"index.html\", \"index.htm\"]. Files are checked in order.","url":"HSHTTPServer.html#setDirectoryIndex","kind":"method"},{"fullName":"HSHTTPServer.setAllowDirectoryListing(allow)","description":"Enable or disable directory listing for requests that map to a directory with no index file. When disabled (the default), directory requests without an index file return 403.","url":"HSHTTPServer.html#setAllowDirectoryListing","kind":"method"},{"fullName":"HSHTTPServer.setTLSFromPKCS12(path, password)","description":"Configure TLS using a PKCS#12 (.p12) identity file. When TLS is configured, the server accepts HTTPS connections. The .p12 file must contain both the certificate and the private key.","url":"HSHTTPServer.html#setTLSFromPKCS12","kind":"method"},{"fullName":"HSHTTPServer.start()","description":"Start the server and begin accepting connections. The server must be configured before calling start(). To restart the server with new settings, call stop() followed by start().","url":"HSHTTPServer.html#start","kind":"method"},{"fullName":"HSHTTPServer.stop()","description":"Stop the server and close all connections.","url":"HSHTTPServer.html#stop","kind":"method"},{"fullName":"HSHTTPServer.destroy()","description":"Destroy this server, releasing all resources. After calling destroy(), the server object should not be used.","url":"HSHTTPServer.html#destroy","kind":"method"},{"fullName":"HSHTTPServer.getPort()","description":"Get the TCP port the server is currently listening on. Returns 0 if the server is not running.","url":"HSHTTPServer.html#getPort","kind":"method"},{"fullName":"HSHTTPServer.getName()","description":"Get the configured Bonjour service name.","url":"HSHTTPServer.html#getName","kind":"method"},{"fullName":"HSHTTPServer.getInterface()","description":"Get the configured network interface, or null if listening on all interfaces.","url":"HSHTTPServer.html#getInterface","kind":"method"},{"fullName":"HSHTTPServer.setWebSocketCallback(path, callback)","description":"Register a WebSocket handler for a URL path. When a client connects and performs a WebSocket upgrade handshake on path, the callback is invoked with three arguments: event (string), connection (HSWebSocketConnection), and message (string). Events: Pass null to remove the WebSocket handler for the path.","url":"HSHTTPServer.html#setWebSocketCallback","kind":"method"},{"fullName":"HSWebSocketConnection","description":"A WebSocket connection to a single client, passed to the callback registered with server.setWebSocketCallback(). Use send() to push messages to the connected client and close() to end the connection. Do not instantiate HSWebSocketConnection directly — it is created by the server when a client performs a WebSocket upgrade.","url":"HSWebSocketConnection.html","kind":"type"},{"fullName":"HSWebSocketConnection.identifier","description":"A unique identifier for this connection (UUID string).","url":"HSWebSocketConnection.html#identifier","kind":"property"},{"fullName":"HSWebSocketConnection.send(message)","description":"Send a text message to the connected WebSocket client.","url":"HSWebSocketConnection.html#send","kind":"method"},{"fullName":"HSWebSocketConnection.close()","description":"Close the WebSocket connection to the client. Sends a WebSocket close frame and cancels the underlying TCP connection.","url":"HSWebSocketConnection.html#close","kind":"method"},{"fullName":"HSWebSocketConnection.destroy()","description":"Destroy this connection object, releasing all resources.","url":"HSWebSocketConnection.html#destroy","kind":"method"},{"fullName":"HSLocationWatcher","description":"An independent location tracking object. Create via hs.location.addWatcher(). Call start() to begin receiving updates, and set a callback to handle them. | Event | Data | |-------|------| | \"location\" | a locationTable | | \"error\" | an error message string | | \"authorizationChanged\" | the new status string (\"authorized\", \"denied\", \"restricted\", \"notDetermined\") |","url":"HSLocationWatcher.html","kind":"type"},{"fullName":"HSLocationWatcher.identifier","description":"The unique identifier assigned to this watcher.","url":"HSLocationWatcher.html#identifier","kind":"property"},{"fullName":"HSLocationWatcher.distanceFilter","description":"The minimum distance in metres the device must move before a new update is delivered. Defaults to kCLDistanceFilterNone (all movements reported).","url":"HSLocationWatcher.html#distanceFilter","kind":"property"},{"fullName":"HSLocationWatcher.start()","description":"Starts location updates. The callback must be set first.","url":"HSLocationWatcher.html#start","kind":"method"},{"fullName":"HSLocationWatcher.stop()","description":"Stops location updates.","url":"HSLocationWatcher.html#stop","kind":"method"},{"fullName":"HSLocationWatcher.setCallback(fn)","description":"Sets the callback function invoked when location events occur.","url":"HSLocationWatcher.html#setCallback","kind":"method"},{"fullName":"HSLocationWatcher.location()","description":"Returns the most recently received location, or null if none yet.","url":"HSLocationWatcher.html#location","kind":"method"},{"fullName":"HSMenuBarItem","description":"Object representing a macOS system menu bar item. Create instances with hs.menubar.create().","url":"HSMenuBarItem.html","kind":"type"},{"fullName":"HSMenuBarItem.title","description":"Get or set the menu item's title.","url":"HSMenuBarItem.html#title","kind":"property"},{"fullName":"HSMenuBarItem.setIcon(image)","description":"Set the icon displayed in the menu bar","url":"HSMenuBarItem.html#setIcon","kind":"method"},{"fullName":"HSMenuBarItem.setTooltip(tooltip)","description":"Set the tooltip shown when hovering over the menu bar item","url":"HSMenuBarItem.html#setTooltip","kind":"method"},{"fullName":"HSMenuBarItem.setClickCallback(fn)","description":"Set a callback invoked when the item is clicked (only fires when no menu is set)","url":"HSMenuBarItem.html#setClickCallback","kind":"method"},{"fullName":"HSMenuBarItem.setMenu(menuOrFn)","description":"Set the menu for this item. Pass an array of menu item objects for a static menu, or a function that returns an array for a dynamic menu populated each time it opens.","url":"HSMenuBarItem.html#setMenu","kind":"method"},{"fullName":"HSMenuBarItem.hide()","description":"Remove this item from the menu bar. The item is retained and can be shown again with show().","url":"HSMenuBarItem.html#hide","kind":"method"},{"fullName":"HSMenuBarItem.show()","description":"Show this item in the menu bar.","url":"HSMenuBarItem.html#show","kind":"method"},{"fullName":"HSMenuBarItem.isVisible()","description":"Check if this item is currently visible in the menu bar.","url":"HSMenuBarItem.html#isVisible","kind":"method"},{"fullName":"HSMenuBarItem.destroy()","description":"Permanently remove this item from the menu bar and release all resources. After calling destroy(), the item is no longer usable. This is called automatically on hs.reload(). Use hide() instead if you only want to temporarily remove the item without freeing it.","url":"HSMenuBarItem.html#destroy","kind":"method"},{"fullName":"HSNetworkConfigurationWatcher","description":"A watcher for System Configuration dynamic store key changes. Create with hs.network.configurationWatcher().","url":"HSNetworkConfigurationWatcher.html","kind":"type"},{"fullName":"HSNetworkConfigurationWatcher.typeName","description":"Always \"HSNetworkConfigurationWatcher\".","url":"HSNetworkConfigurationWatcher.html#typeName","kind":"property"},{"fullName":"HSNetworkConfigurationWatcher.setKeys(keys, pattern)","description":"Specifies which dynamic store keys (or key patterns) to watch for changes. Must be called before start(). Each element of keys is treated as a string literal when pattern is false (the default), or as a regular expression when pattern is true. Calling setKeys again replaces the previous set of watched keys.","url":"HSNetworkConfigurationWatcher.html#setKeys","kind":"method"},{"fullName":"HSNetworkConfigurationWatcher.setCallback(callback)","description":"Sets the callback invoked when a watched key changes. The callback receives (watcher, changedKeys) where changedKeys is an array of key strings that changed since the last notification. Call hs.network.configurationStore() inside the callback to read the updated values.","url":"HSNetworkConfigurationWatcher.html#setCallback","kind":"method"},{"fullName":"HSNetworkConfigurationWatcher.start()","description":"Starts watching for dynamic store changes. The callback registered with setCallback() will be invoked whenever a key matching the patterns registered with setKeys() changes. Call setKeys() and setCallback() before calling start().","url":"HSNetworkConfigurationWatcher.html#start","kind":"method"},{"fullName":"HSNetworkConfigurationWatcher.stop()","description":"Stops watching for dynamic store changes. The callback will no longer be invoked. Call start() again to resume monitoring.","url":"HSNetworkConfigurationWatcher.html#stop","kind":"method"},{"fullName":"HSNetworkPing","description":"Object representing an active or completed ICMP ping operation. Create instances with hs.network.ping().","url":"HSNetworkPing.html","kind":"type"},{"fullName":"HSNetworkPing.typeName","description":"Always \"HSNetworkPing\".","url":"HSNetworkPing.html#typeName","kind":"property"},{"fullName":"HSNetworkPing.address","description":"The resolved IP address of the target, or \"\" if DNS has not yet completed.","url":"HSNetworkPing.html#address","kind":"property"},{"fullName":"HSNetworkPing.server","description":"The hostname or IP address string originally passed to hs.network.ping().","url":"HSNetworkPing.html#server","kind":"property"},{"fullName":"HSNetworkPing.sent","description":"The number of ICMP Echo Requests sent so far.","url":"HSNetworkPing.html#sent","kind":"property"},{"fullName":"HSNetworkPing.count","description":"The total number of ICMP Echo Requests to send. May be increased while the ping is running provided the new value is greater than the number already sent.","url":"HSNetworkPing.html#count","kind":"property"},{"fullName":"HSNetworkPing.isRunning","description":"true while the ping is actively sending and waiting for replies.","url":"HSNetworkPing.html#isRunning","kind":"property"},{"fullName":"HSNetworkPing.isPaused","description":"true when the ping has been suspended with pause().","url":"HSNetworkPing.html#isPaused","kind":"property"},{"fullName":"HSNetworkPing.packets(sequenceNumber)","description":"Returns packet statistics for all sent packets, or for a single packet by its zero-based sequence number.","url":"HSNetworkPing.html#packets","kind":"method"},{"fullName":"HSNetworkPing.summary()","description":"Returns a human-readable summary of the ping results in standard ping format.","url":"HSNetworkPing.html#summary","kind":"method"},{"fullName":"HSNetworkPing.pause()","description":"Suspends the ping. No further packets are sent until resume() is called.","url":"HSNetworkPing.html#pause","kind":"method"},{"fullName":"HSNetworkPing.resume()","description":"Resumes a paused ping, continuing from where it left off.","url":"HSNetworkPing.html#resume","kind":"method"},{"fullName":"HSNetworkPing.cancel()","description":"Immediately stops the ping, firing the \"didFinish\" callback with statistics collected so far.","url":"HSNetworkPing.html#cancel","kind":"method"},{"fullName":"HSNetworkPing.setCallback(callback)","description":"Replaces the ping's callback function.","url":"HSNetworkPing.html#setCallback","kind":"method"},{"fullName":"HSNetworkReachability","description":"An active or inactive network reachability monitor. Create with hs.network.reachability*().","url":"HSNetworkReachability.html","kind":"type"},{"fullName":"HSNetworkReachability.typeName","description":"Always \"HSNetworkReachability\".","url":"HSNetworkReachability.html#typeName","kind":"property"},{"fullName":"HSNetworkReachability.status()","description":"Returns the current reachability flags as a numeric bitmask. Compare against constants in hs.network.reachabilityFlags. Returns 0 if the network is currently unreachable.","url":"HSNetworkReachability.html#status","kind":"method"},{"fullName":"HSNetworkReachability.statusString()","description":"Returns a human-readable summary of the current reachability flags. The string contains 8 characters in order: t (transient/expensive), R (reachable), c (connectionRequired), C (connectionOnTraffic — always -), i (interventionRequired/constrained), D (connectionOnDemand — always -), l (isLocalAddress — always -), d (isDirect). A letter appears when that flag is set; - appears when it is clear.","url":"HSNetworkReachability.html#statusString","kind":"method"},{"fullName":"HSNetworkReachability.setCallback(callback)","description":"Replaces the callback invoked when reachability changes. The callback receives (reachability, flags) where flags is the same numeric bitmask as returned by status(). Call start() after setCallback() to begin monitoring.","url":"HSNetworkReachability.html#setCallback","kind":"method"},{"fullName":"HSNetworkReachability.start()","description":"Starts monitoring for reachability changes. After calling start(), the callback registered with setCallback() is invoked whenever the reachability status changes.","url":"HSNetworkReachability.html#start","kind":"method"},{"fullName":"HSNetworkReachability.stop()","description":"Stops monitoring for reachability changes. The callback will no longer be invoked. Call start() again to resume monitoring.","url":"HSNetworkReachability.html#stop","kind":"method"},{"fullName":"HSNotification","description":"A notification created by hs.notify.new(). Call .send() to deliver it to macOS Notification Center. You can hold a reference to the object and call .withdraw() later to remove it.","url":"HSNotification.html","kind":"type"},{"fullName":"HSNotification.identifier","description":"The unique identifier assigned to this notification. Use it to correlate with system notification APIs if needed.","url":"HSNotification.html#identifier","kind":"property"},{"fullName":"HSNotification.send()","description":"Deliver this notification immediately to Notification Center.","url":"HSNotification.html#send","kind":"method"},{"fullName":"HSNotification.withdraw()","description":"Remove this notification from Notification Center (if delivered) or cancel it (if pending).","url":"HSNotification.html#withdraw","kind":"method"},{"fullName":"HSOCRObservation","description":"A single region of text recognized in an image. Instances are delivered inside the observations array of an HSOCRResult. Each observation represents a discrete text run found in the source image, along with a confidence score and a normalized bounding box. (0, 0) is the top-left corner of the image and (1, 1) is the bottom-right. This matches the convention used by most image-processing tools and differs from Vision's internal bottom-left-origin system (the conversion is automatic).","url":"HSOCRObservation.html","kind":"type"},{"fullName":"HSOCRObservation.typeName","description":"The Swift type name, for JavaScript introspection.","url":"HSOCRObservation.html#typeName","kind":"property"},{"fullName":"HSOCRObservation.text","description":"The recognized text string for this observation.","url":"HSOCRObservation.html#text","kind":"property"},{"fullName":"HSOCRObservation.confidence","description":"Recognition confidence in the range 0.0 (uncertain) to 1.0 (certain). Use minimumConfidence in the options passed to recognizeText() to pre-filter observations below a threshold rather than filtering here.","url":"HSOCRObservation.html#confidence","kind":"property"},{"fullName":"HSOCRObservation.bounds","description":"Normalized bounding box of this observation in the source image, as an HSRect. All values are in the range 0–1 with top-left origin ((0, 0) = top-left corner, (1, 1) = bottom-right corner). Use bounds.x, bounds.y, bounds.w, and bounds.h to access the components.","url":"HSOCRObservation.html#bounds","kind":"property"},{"fullName":"HSOCRResult","description":"The result of a text recognition operation on an image. An HSOCRResult is returned by hs.ocr.recognizeText() and bundles the full recognized text together with an array of per-region observations, each carrying its own confidence score and bounding box.","url":"HSOCRResult.html","kind":"type"},{"fullName":"HSOCRResult.typeName","description":"The Swift type name, for JavaScript introspection.","url":"HSOCRResult.html#typeName","kind":"property"},{"fullName":"HSOCRResult.text","description":"The full recognized text from the image, with each observation's text joined by newlines in the order Vision returned them. Use this when you only need the raw text and don't care about bounding boxes or per-region confidence scores.","url":"HSOCRResult.html#text","kind":"property"},{"fullName":"HSOCRResult.observations","description":"The individual text observations that make up this result. Each entry in the array is an HSOCRObservation with its own text, confidence, and bounds properties. Observations are returned in the order Vision produced them (typically top-to-bottom, left-to-right, but this is image-dependent).","url":"HSOCRResult.html#observations","kind":"property"},{"fullName":"HSScreen","description":"An object representing a single display attached to the system. ## Coordinate system All geometry is returned in Hammerspoon screen coordinates: the origin (0, 0) is at the top-left of the primary display, and y increases downward. This matches Hammerspoon v1 and is the inverse of the raw macOS/CoreGraphics convention. ## Examples ``javascript const s = hs.screen.main(); console.log(s.name); // e.g. \"Built-in Retina Display\" console.log(s.frame.w); // usable width in points","url":"HSScreen.html","kind":"type"},{"fullName":"HSScreen.id","description":"Unique display identifier (matches CGDirectDisplayID).","url":"HSScreen.html#id","kind":"property"},{"fullName":"HSScreen.name","description":"The manufacturer-assigned localized display name.","url":"HSScreen.html#name","kind":"property"},{"fullName":"HSScreen.uuid","description":"The display's UUID string.","url":"HSScreen.html#uuid","kind":"property"},{"fullName":"HSScreen.frame","description":"The usable screen area in Hammerspoon coordinates, excluding the menu bar and Dock.","url":"HSScreen.html#frame","kind":"property"},{"fullName":"HSScreen.fullFrame","description":"The full screen area in Hammerspoon coordinates, including menu bar and Dock regions.","url":"HSScreen.html#fullFrame","kind":"property"},{"fullName":"HSScreen.position","description":"The screen's top-left corner in global Hammerspoon coordinates.","url":"HSScreen.html#position","kind":"property"},{"fullName":"HSScreen.mode","description":"The currently active display mode. An object with keys: width, height, scale, frequency.","url":"HSScreen.html#mode","kind":"property"},{"fullName":"HSScreen.availableModes","description":"All display modes supported by this screen. Each element has keys: width, height, scale, frequency.","url":"HSScreen.html#availableModes","kind":"property"},{"fullName":"HSScreen.rotation","description":"The current screen rotation in degrees (0, 90, 180, or 270). Assign one of 0, 90, 180, or 270 to rotate the display.","url":"HSScreen.html#rotation","kind":"property"},{"fullName":"HSScreen.desktopImage","description":"The URL string of the current desktop background image for this screen, or null. Assign a new absolute file path or file:// URL string to change the wallpaper.","url":"HSScreen.html#desktopImage","kind":"property"},{"fullName":"HSScreen.ambientLight","description":"The ambient light level measured by this display's built-in sensor, in lux. Returns null if the display does not have an ambient light sensor or if the reading is currently unavailable.","url":"HSScreen.html#ambientLight","kind":"property"},{"fullName":"HSScreen.setMode(width, height, scale, frequency)","description":"Switch to the given display mode. Pass 0 for scale or frequency to match any value.","url":"HSScreen.html#setMode","kind":"method"},{"fullName":"HSScreen.snapshot()","description":"Capture the current contents of this screen as an image. Requires Screen Recording permission.","url":"HSScreen.html#snapshot","kind":"method"},{"fullName":"HSScreen.next()","description":"The next screen in hs.screen.all() order, wrapping around.","url":"HSScreen.html#next","kind":"method"},{"fullName":"HSScreen.previous()","description":"The previous screen in hs.screen.all() order, wrapping around.","url":"HSScreen.html#previous","kind":"method"},{"fullName":"HSScreen.toEast()","description":"The nearest screen whose left edge is at or beyond this screen's right edge, or null.","url":"HSScreen.html#toEast","kind":"method"},{"fullName":"HSScreen.toWest()","description":"The nearest screen whose right edge is at or before this screen's left edge, or null.","url":"HSScreen.html#toWest","kind":"method"},{"fullName":"HSScreen.toNorth()","description":"The nearest screen that is physically above this screen, or null.","url":"HSScreen.html#toNorth","kind":"method"},{"fullName":"HSScreen.toSouth()","description":"The nearest screen that is physically below this screen, or null.","url":"HSScreen.html#toSouth","kind":"method"},{"fullName":"HSScreen.setOrigin(x, y)","description":"Move this screen so its top-left corner is at the given position in global Hammerspoon coordinates.","url":"HSScreen.html#setOrigin","kind":"method"},{"fullName":"HSScreen.setPrimary()","description":"Designate this screen as the primary display (moves the menu bar here).","url":"HSScreen.html#setPrimary","kind":"method"},{"fullName":"HSScreen.mirrorOf(screen)","description":"Configure this screen to mirror another screen.","url":"HSScreen.html#mirrorOf","kind":"method"},{"fullName":"HSScreen.mirrorStop()","description":"Stop mirroring, restoring this screen to an independent display.","url":"HSScreen.html#mirrorStop","kind":"method"},{"fullName":"HSScreen.absoluteToLocal(rect)","description":"Convert a rect in global Hammerspoon coordinates to coordinates local to this screen. The result origin is relative to this screen's top-left corner.","url":"HSScreen.html#absoluteToLocal","kind":"method"},{"fullName":"HSScreen.localToAbsolute(rect)","description":"Convert a rect in local screen coordinates to global Hammerspoon coordinates.","url":"HSScreen.html#localToAbsolute","kind":"method"},{"fullName":"HSSound","description":"An object representing an audio sound that can be played, paused, and stopped. Create instances using hs.sound.fromFile() or hs.sound.named().","url":"HSSound.html","kind":"type"},{"fullName":"HSSound.identifier","description":"A unique identifier for this sound object.","url":"HSSound.html#identifier","kind":"property"},{"fullName":"HSSound.name","description":"The name of this sound. System sounds loaded by name return their name; file-based sounds return null.","url":"HSSound.html#name","kind":"property"},{"fullName":"HSSound.duration","description":"The total duration of the sound in seconds.","url":"HSSound.html#duration","kind":"property"},{"fullName":"HSSound.currentTime","description":"The current playback position in seconds. Assign a value to seek to that position.","url":"HSSound.html#currentTime","kind":"property"},{"fullName":"HSSound.volume","description":"The playback volume, from 0.0 (silent) to 1.0 (full volume).","url":"HSSound.html#volume","kind":"property"},{"fullName":"HSSound.loops","description":"Whether the sound loops when it reaches the end. Defaults to false.","url":"HSSound.html#loops","kind":"property"},{"fullName":"HSSound.isPlaying","description":"Whether the sound is currently playing.","url":"HSSound.html#isPlaying","kind":"property"},{"fullName":"HSSound.play()","description":"Starts playback from the current position.","url":"HSSound.html#play","kind":"method"},{"fullName":"HSSound.pause()","description":"Pauses playback, preserving the current position.","url":"HSSound.html#pause","kind":"method"},{"fullName":"HSSound.resume()","description":"Resumes playback from a paused position.","url":"HSSound.html#resume","kind":"method"},{"fullName":"HSSound.stop()","description":"Stops playback. The playback position is not reset.","url":"HSSound.html#stop","kind":"method"},{"fullName":"HSSound.setCallback(callback)","description":"Sets a function to be called when playback finishes. The callback receives two arguments: the sound object and a boolean — true if the sound completed naturally, false if it was stopped before finishing.","url":"HSSound.html#setCallback","kind":"method"},{"fullName":"HSSound.removeCallback()","description":"Removes the completion callback previously set with setCallback().","url":"HSSound.html#removeCallback","kind":"method"},{"fullName":"HSSound.destroy()","description":"Stops playback and releases all resources held by this sound. After calling destroy() the sound object should not be used.","url":"HSSound.html#destroy","kind":"method"},{"fullName":"HSSpotlightGroup","description":"A grouped set of Spotlight results that share a common metadata attribute value. Groups are returned by HSSpotlightQuery.groups() when grouping attributes have been configured with setGroupingAttributes(). Do not instantiate HSSpotlightGroup directly. When multiple grouping attributes are specified, groups nest: each group has subgroups() containing the next level of grouping.","url":"HSSpotlightGroup.html","kind":"type"},{"fullName":"HSSpotlightGroup.identifier","description":"A unique identifier for this group object (UUID string).","url":"HSSpotlightGroup.html#identifier","kind":"property"},{"fullName":"HSSpotlightGroup.attribute","description":"The metadata attribute name by which results in this group are clustered.","url":"HSSpotlightGroup.html#attribute","kind":"property"},{"fullName":"HSSpotlightGroup.count","description":"The number of results contained in this group.","url":"HSSpotlightGroup.html#count","kind":"property"},{"fullName":"HSSpotlightGroup.value()","description":"The shared value of the grouping attribute for all results in this group. Returns null only in the unlikely case that the underlying value cannot be bridged.","url":"HSSpotlightGroup.html#value","kind":"method"},{"fullName":"HSSpotlightGroup.results()","description":"Returns the items contained in this group as an array of HSSpotlightItem objects.","url":"HSSpotlightGroup.html#results","kind":"method"},{"fullName":"HSSpotlightGroup.subgroups()","description":"Returns nested subgroups when multiple grouping attributes were specified. Returns an empty array if no subgroups exist for this group.","url":"HSSpotlightGroup.html#subgroups","kind":"method"},{"fullName":"HSSpotlightItem","description":"An individual result returned by a Spotlight query. Instances are returned by HSSpotlightQuery.results() and related methods. Do not instantiate HSSpotlightItem directly. Metadata values are read via valueForAttribute() using standard kMDItem* keys. Call attributes() to discover which keys are populated on a particular item. Common attribute key shortcuts live in hs.spotlight.attribute.","url":"HSSpotlightItem.html","kind":"type"},{"fullName":"HSSpotlightItem.identifier","description":"A unique identifier for this result object (UUID string).","url":"HSSpotlightItem.html#identifier","kind":"property"},{"fullName":"HSSpotlightItem.attributes()","description":"Returns the list of metadata attribute names present on this item. The list is typically not exhaustive — some attributes (such as kMDItemPath) may be readable via valueForAttribute() even when absent from this list.","url":"HSSpotlightItem.html#attributes","kind":"method"},{"fullName":"HSSpotlightItem.valueForAttribute(key)","description":"Returns the value for a specific metadata attribute, or null if absent. The return type depends on the attribute: common types include strings, numbers, dates, and arrays of strings. NSURL-typed values are automatically converted to their string representation.","url":"HSSpotlightItem.html#valueForAttribute","kind":"method"},{"fullName":"HSSpotlightQuery","description":"A configurable Spotlight search query that can be started, stopped, and queried for results. Create instances via hs.spotlight.create() or the convenience helper hs.spotlight.search(). Configure the query with chainable setter methods, register a callback, then call start(). Results accumulate during the initial gathering phase (\"didStart\" → \"inProgress\" → \"didFinish\") and continue to update during the live-monitoring phase (\"didUpdate\"). Stop explicitly with stop() when you no longer need live updates.","url":"HSSpotlightQuery.html","kind":"type"},{"fullName":"HSSpotlightQuery.identifier","description":"A unique identifier for this query object (UUID string).","url":"HSSpotlightQuery.html#identifier","kind":"property"},{"fullName":"HSSpotlightQuery.count","description":"The number of results gathered so far.","url":"HSSpotlightQuery.html#count","kind":"property"},{"fullName":"HSSpotlightQuery.isRunning","description":"Whether the query is currently running (gathering or monitoring for live updates).","url":"HSSpotlightQuery.html#isRunning","kind":"property"},{"fullName":"HSSpotlightQuery.isGathering","description":"Whether the query is in the initial gathering phase. true from \"didStart\" until \"didFinish\"; false thereafter while live-monitoring.","url":"HSSpotlightQuery.html#isGathering","kind":"property"},{"fullName":"HSSpotlightQuery.setQuery(predicate)","description":"Sets the NSPredicate query string for this search. The string must be a valid NSPredicate format expression using kMDItem* attribute keys and MDQuery operators (==, !=, <, >, BEGINSWITH, CONTAINS, etc.). If the query is already running when this is called, it is stopped and restarted automatically.","url":"HSSpotlightQuery.html#setQuery","kind":"method"},{"fullName":"HSSpotlightQuery.setScopes(scopes)","description":"Sets the search scopes that restrict where Spotlight looks. Pass an array of predefined scope strings from hs.spotlight.scope, absolute directory paths, or a mix of both. Paths beginning with ~ are expanded to the user's home directory. When not set, the query defaults to hs.spotlight.scope.computer.","url":"HSSpotlightQuery.html#setScopes","kind":"method"},{"fullName":"HSSpotlightQuery.setSortDescriptors(descriptors)","description":"Sets sort descriptors that control the order of results.","url":"HSSpotlightQuery.html#setSortDescriptors","kind":"method"},{"fullName":"HSSpotlightQuery.setGroupingAttributes(attrs)","description":"Sets the attributes by which results will be grouped. When grouping attributes are set, use groups() to retrieve results organised into HSSpotlightGroup objects. Specifying multiple attributes creates nested subgroups accessible via group.subgroups().","url":"HSSpotlightQuery.html#setGroupingAttributes","kind":"method"},{"fullName":"HSSpotlightQuery.setValueListAttributes(attrs)","description":"Sets the attributes for which aggregate value-list summaries are computed. After the query finishes, valueLists() returns aggregate data for each specified attribute: distinct values and the number of results carrying each value.","url":"HSSpotlightQuery.html#setValueListAttributes","kind":"method"},{"fullName":"HSSpotlightQuery.setCallback(fn)","description":"Registers a callback that receives query lifecycle events. of HSSpotlightItem objects describing what changed in this update cycle","url":"HSSpotlightQuery.html#setCallback","kind":"method"},{"fullName":"HSSpotlightQuery.start()","description":"Starts the query. The query must have a predicate set (via setQuery()) before calling start(). Calling start() on an already-running query is a no-op.","url":"HSSpotlightQuery.html#start","kind":"method"},{"fullName":"HSSpotlightQuery.stop()","description":"Stops the query while preserving accumulated results. After stopping, results(), count, groups(), and valueLists() continue to return the last gathered data. Call start() again to resume.","url":"HSSpotlightQuery.html#stop","kind":"method"},{"fullName":"HSSpotlightQuery.results()","description":"Returns the current results as an array of HSSpotlightItem objects. The result set is briefly frozen during access to ensure consistency. Safe to call from within a query callback.","url":"HSSpotlightQuery.html#results","kind":"method"},{"fullName":"HSSpotlightQuery.groups()","description":"Returns grouped results when grouping attributes have been configured. Returns an empty array if setGroupingAttributes() was not called.","url":"HSSpotlightQuery.html#groups","kind":"method"},{"fullName":"HSSpotlightQuery.valueLists()","description":"Returns aggregate value-list summaries for attributes set via setValueListAttributes(). Returns an empty array if setValueListAttributes() was not called.","url":"HSSpotlightQuery.html#valueLists","kind":"method"},{"fullName":"HSTask","description":"Object representing an external process task","url":"HSTask.html","kind":"type"},{"fullName":"HSTask.isRunning","description":"Check if the task is currently running","url":"HSTask.html#isRunning","kind":"property"},{"fullName":"HSTask.pid","description":"The process ID of the running task","url":"HSTask.html#pid","kind":"property"},{"fullName":"HSTask.environment","description":"The environment variables for the task","url":"HSTask.html#environment","kind":"property"},{"fullName":"HSTask.workingDirectory","description":"The working directory for the task","url":"HSTask.html#workingDirectory","kind":"property"},{"fullName":"HSTask.terminationStatus","description":"The termination status of the task","url":"HSTask.html#terminationStatus","kind":"property"},{"fullName":"HSTask.terminationReason","description":"The termination reason","url":"HSTask.html#terminationReason","kind":"property"},{"fullName":"HSTask.start()","description":"Start the task","url":"HSTask.html#start","kind":"method"},{"fullName":"HSTask.terminate()","description":"Terminate the task (send SIGTERM)","url":"HSTask.html#terminate","kind":"method"},{"fullName":"HSTask.kill9()","description":"Terminate the task with extreme prejudice (send SIGKILL)","url":"HSTask.html#kill9","kind":"method"},{"fullName":"HSTask.interrupt()","description":"Interrupt the task (send SIGINT)","url":"HSTask.html#interrupt","kind":"method"},{"fullName":"HSTask.pause()","description":"Pause the task (send SIGSTOP)","url":"HSTask.html#pause","kind":"method"},{"fullName":"HSTask.resume()","description":"Resume the task (send SIGCONT)","url":"HSTask.html#resume","kind":"method"},{"fullName":"HSTask.waitUntilExit()","description":"Wait for the task to complete (blocking)","url":"HSTask.html#waitUntilExit","kind":"method"},{"fullName":"HSTask.sendInput(data)","description":"Write data to the task's stdin","url":"HSTask.html#sendInput","kind":"method"},{"fullName":"HSTask.closeInput()","description":"Close the task's stdin","url":"HSTask.html#closeInput","kind":"method"},{"fullName":"HSTimer","description":"Object representing a timer. You should not instantiate these yourself, but rather, use the methods in hs.timer to create them for you.","url":"HSTimer.html","kind":"type"},{"fullName":"HSTimer.interval","description":"The timer's interval in seconds","url":"HSTimer.html#interval","kind":"property"},{"fullName":"HSTimer.repeats","description":"Whether the timer repeats","url":"HSTimer.html#repeats","kind":"property"},{"fullName":"HSTimer.start()","description":"Start the timer","url":"HSTimer.html#start","kind":"method"},{"fullName":"HSTimer.stop()","description":"Stop the timer","url":"HSTimer.html#stop","kind":"method"},{"fullName":"HSTimer.fire()","description":"Immediately fire the timer's callback","url":"HSTimer.html#fire","kind":"method"},{"fullName":"HSTimer.running()","description":"Check if the timer is currently running","url":"HSTimer.html#running","kind":"method"},{"fullName":"HSTimer.nextTrigger()","description":"Get the number of seconds until the timer next fires","url":"HSTimer.html#nextTrigger","kind":"method"},{"fullName":"HSTimer.setNextTrigger(seconds)","description":"Set when the timer should next fire","url":"HSTimer.html#setNextTrigger","kind":"method"},{"fullName":"HSTranslationSession","description":"JavaScript-visible API for a translation session bound to a specific language pair.","url":"HSTranslationSession.html","kind":"type"},{"fullName":"HSTranslationSession.typeName","description":"The Swift type name, for JavaScript introspection.","url":"HSTranslationSession.html#typeName","kind":"property"},{"fullName":"HSTranslationSession.sourceLanguage","description":"BCP-47 identifier of the source language (e.g. \"en\").","url":"HSTranslationSession.html#sourceLanguage","kind":"property"},{"fullName":"HSTranslationSession.targetLanguage","description":"BCP-47 identifier of the target language (e.g. \"fr\").","url":"HSTranslationSession.html#targetLanguage","kind":"property"},{"fullName":"HSTranslationSession.translate(text)","description":"Translate a string from the session's source language to its target language.","url":"HSTranslationSession.html#translate","kind":"method"},{"fullName":"HSUIWindow","description":"# HSUIWindow A custom window with declarative UI building HSUIWindow allows you to create custom windows with a SwiftUI-like declarative syntax. Build interfaces using shapes, text, images, and layout containers. ## Building UI Elements ## Modifying Elements ## Examples Simple window with text and shapes: ``javascript hs.ui.window({x: 100, y: 100, w: 300, h: 200}) .vstack() .spacing(10) .padding(20) .text(\"Dashboard\") .font(HSFont.largeTitle()) .foregroundColor(\"#FFFFFF\") .rectangle() .fill(\"#4A90E2\") .cornerRadius(10) .frame({w: \"90%\", h: 80}) .end() .backgroundColor(\"#2C3E50\") .show(); ` Window with image: `javascript const img = HSImage.fromPath(\"~/Pictures/photo.jpg\") hs.ui.window({x: 100, y: 100, w: 400, h: 300}) .vstack() .padding(20) .image(img) .resizable() .aspectRatio(\"fit\") .frame({w: 360, h: 240}) .end() .show(); ``","url":"HSUIWindow.html","kind":"type"},{"fullName":"HSUIWindow.show()","description":"Show the window","url":"HSUIWindow.html#show","kind":"method"},{"fullName":"HSUIWindow.hide()","description":"Hide the window (keeps it in memory)","url":"HSUIWindow.html#hide","kind":"method"},{"fullName":"HSUIWindow.close()","description":"Close and destroy the window","url":"HSUIWindow.html#close","kind":"method"},{"fullName":"HSUIWindow.titled(show)","description":"Show or hide the window's title bar By default windows have a title bar. Pass false to create a borderless window. .closable(), .miniaturizable(), and .allowResize() only take visual effect when the window is titled.","url":"HSUIWindow.html#titled","kind":"method"},{"fullName":"HSUIWindow.closable(show)","description":"Show or hide the close button on the window Requires .titled(true) to be visible. Enabled by default.","url":"HSUIWindow.html#closable","kind":"method"},{"fullName":"HSUIWindow.miniaturizable(show)","description":"Show or hide the miniaturize (yellow) button on the window Requires .titled(true) to be visible. Enabled by default.","url":"HSUIWindow.html#miniaturizable","kind":"method"},{"fullName":"HSUIWindow.allowResize(enable)","description":"Allow or prevent the user from resizing the window Enabled by default. Only has a visual effect when .titled(true) is also set.","url":"HSUIWindow.html#allowResize","kind":"method"},{"fullName":"HSUIWindow.windowTitle(text)","description":"Set the text shown in the window's title bar Only visible when .titled(true) is set (the default).","url":"HSUIWindow.html#windowTitle","kind":"method"},{"fullName":"HSUIWindow.level(name)","description":"Set the window stacking level Controls where this window sits in the macOS window hierarchy.","url":"HSUIWindow.html#level","kind":"method"},{"fullName":"HSUIWindow.backgroundColor(colorValue)","description":"Set the window's background color","url":"HSUIWindow.html#backgroundColor","kind":"method"},{"fullName":"HSUIWindow.rectangle()","description":"Add a rectangle shape","url":"HSUIWindow.html#rectangle","kind":"method"},{"fullName":"HSUIWindow.circle()","description":"Add a circle shape","url":"HSUIWindow.html#circle","kind":"method"},{"fullName":"HSUIWindow.text(content)","description":"Add a text element or an HSString object (from hs.ui.string()) for reactive text","url":"HSUIWindow.html#text","kind":"method"},{"fullName":"HSUIWindow.image(imageValue)","description":"Add an image element","url":"HSUIWindow.html#image","kind":"method"},{"fullName":"HSUIWindow.button(label)","description":"Add a button element or an HSString object (from hs.ui.string()) for reactive text","url":"HSUIWindow.html#button","kind":"method"},{"fullName":"HSUIWindow.vstack()","description":"Begin a vertical stack (elements arranged top to bottom)","url":"HSUIWindow.html#vstack","kind":"method"},{"fullName":"HSUIWindow.hstack()","description":"Begin a horizontal stack (elements arranged left to right)","url":"HSUIWindow.html#hstack","kind":"method"},{"fullName":"HSUIWindow.zstack()","description":"Begin a z-stack (overlapping elements)","url":"HSUIWindow.html#zstack","kind":"method"},{"fullName":"HSUIWindow.spacer()","description":"Add flexible spacing that expands to fill available space","url":"HSUIWindow.html#spacer","kind":"method"},{"fullName":"HSUIWindow.webview(element)","description":"Embed a web browser element created with hs.ui.webview() (macOS 26+) The element fills the available space in the window layout. Keep a reference to the element to call navigation methods after the window is shown.","url":"HSUIWindow.html#webview","kind":"method"},{"fullName":"HSUIWindow.end()","description":"End the current layout container","url":"HSUIWindow.html#end","kind":"method"},{"fullName":"HSUIWindow.fill(colorValue)","description":"Fill a shape with a color","url":"HSUIWindow.html#fill","kind":"method"},{"fullName":"HSUIWindow.stroke(colorValue)","description":"Add a stroke (border) to a shape","url":"HSUIWindow.html#stroke","kind":"method"},{"fullName":"HSUIWindow.strokeWidth(width)","description":"Set the stroke width","url":"HSUIWindow.html#strokeWidth","kind":"method"},{"fullName":"HSUIWindow.cornerRadius(radius)","description":"Round the corners of a shape","url":"HSUIWindow.html#cornerRadius","kind":"method"},{"fullName":"HSUIWindow.frame(dict)","description":"Set the frame (size) of an element","url":"HSUIWindow.html#frame","kind":"method"},{"fullName":"HSUIWindow.opacity(value)","description":"Set the opacity of an element","url":"HSUIWindow.html#opacity","kind":"method"},{"fullName":"HSUIWindow.font(font)","description":"Set the font for a text element","url":"HSUIWindow.html#font","kind":"method"},{"fullName":"HSUIWindow.foregroundColor(colorValue)","description":"Set the text color","url":"HSUIWindow.html#foregroundColor","kind":"method"},{"fullName":"HSUIWindow.resizable()","description":"Make an image resizable (allows it to scale with frame size)","url":"HSUIWindow.html#resizable","kind":"method"},{"fullName":"HSUIWindow.aspectRatio(mode)","description":"Set the aspect ratio mode for an image","url":"HSUIWindow.html#aspectRatio","kind":"method"},{"fullName":"HSUIWindow.padding(value)","description":"Add padding around a layout container","url":"HSUIWindow.html#padding","kind":"method"},{"fullName":"HSUIWindow.spacing(value)","description":"Set spacing between elements in a stack","url":"HSUIWindow.html#spacing","kind":"method"},{"fullName":"HSUIWindow.onClick(callback)","description":"Set a callback to fire when the element is clicked","url":"HSUIWindow.html#onClick","kind":"method"},{"fullName":"HSUIWindow.onHover(callback)","description":"Set a callback to fire when the cursor enters or leaves the element","url":"HSUIWindow.html#onHover","kind":"method"},{"fullName":"HSUIAlert","description":"# HSUIAlert A temporary on-screen notification Displays a message that automatically fades out after a specified duration. Positioned in the center of the screen with a semi-transparent background. ## Example ``javascript hs.ui.alert(\"Task completed!\") .font(HSFont.headline()) .duration(5) .padding(30) .show(); ``","url":"HSUIAlert.html","kind":"type"},{"fullName":"HSUIAlert.font(font)","description":"Set the font for the alert text","url":"HSUIAlert.html#font","kind":"method"},{"fullName":"HSUIAlert.duration(seconds)","description":"Set how long the alert is displayed","url":"HSUIAlert.html#duration","kind":"method"},{"fullName":"HSUIAlert.padding(points)","description":"Set the padding around the alert text","url":"HSUIAlert.html#padding","kind":"method"},{"fullName":"HSUIAlert.position(dict)","description":"Set a custom position for the alert","url":"HSUIAlert.html#position","kind":"method"},{"fullName":"HSUIAlert.show()","description":"Show the alert","url":"HSUIAlert.html#show","kind":"method"},{"fullName":"HSUIAlert.close()","description":"Close the alert immediately","url":"HSUIAlert.html#close","kind":"method"},{"fullName":"HSUIDialog","description":"# HSUIDialog A modal dialog with customizable buttons Shows a blocking dialog with a message, optional informative text, and custom buttons. Use the callback to respond to button presses. ## Example ``javascript hs.ui.dialog(\"Save changes?\") .informativeText(\"Your document has unsaved changes.\") .buttons([\"Save\", \"Don't Save\", \"Cancel\"]) .onButton((index) => { if (index === 0) { console.log(\"Saving...\"); } else if (index === 1) { console.log(\"Discarding changes...\"); } }) .show(); ``","url":"HSUIDialog.html","kind":"type"},{"fullName":"HSUIDialog.informativeText(text)","description":"Set additional informative text below the main message","url":"HSUIDialog.html#informativeText","kind":"method"},{"fullName":"HSUIDialog.buttons(labels)","description":"Set custom button labels","url":"HSUIDialog.html#buttons","kind":"method"},{"fullName":"HSUIDialog.style(style)","description":"Set the dialog style","url":"HSUIDialog.html#style","kind":"method"},{"fullName":"HSUIDialog.onButton(callback)","description":"Set the callback for button presses","url":"HSUIDialog.html#onButton","kind":"method"},{"fullName":"HSUIDialog.show()","description":"Show the dialog","url":"HSUIDialog.html#show","kind":"method"},{"fullName":"HSUIDialog.close()","description":"Close the dialog programmatically","url":"HSUIDialog.html#close","kind":"method"},{"fullName":"HSUIFilePicker","description":"# HSUIFilePicker A file or directory selection dialog Shows a standard macOS open panel for selecting files or directories. Supports multiple selection, file type filtering, and more. ## Examples ### File Picker ``javascript hs.ui.filePicker() .message(\"Choose a file to open\") .allowedFileTypes([\"txt\", \"md\", \"js\"]) .onSelection((path) => { if (path) { console.log(\"Selected: \" + path); } else { console.log(\"User cancelled\"); } }) .show(); ` ### Directory Picker with Multiple Selection `javascript hs.ui.filePicker() .message(\"Choose directories to backup\") .canChooseFiles(false) .canChooseDirectories(true) .allowsMultipleSelection(true) .onSelection((paths) => { if (paths) { paths.forEach(p => console.log(\"Dir: \" + p)); } }) .show(); ``","url":"HSUIFilePicker.html","kind":"type"},{"fullName":"HSUIFilePicker.message(text)","description":"Set the message displayed in the picker","url":"HSUIFilePicker.html#message","kind":"method"},{"fullName":"HSUIFilePicker.defaultPath(path)","description":"Set the starting directory","url":"HSUIFilePicker.html#defaultPath","kind":"method"},{"fullName":"HSUIFilePicker.canChooseFiles(value)","description":"Set whether files can be selected","url":"HSUIFilePicker.html#canChooseFiles","kind":"method"},{"fullName":"HSUIFilePicker.canChooseDirectories(value)","description":"Set whether directories can be selected","url":"HSUIFilePicker.html#canChooseDirectories","kind":"method"},{"fullName":"HSUIFilePicker.allowsMultipleSelection(value)","description":"Set whether multiple items can be selected","url":"HSUIFilePicker.html#allowsMultipleSelection","kind":"method"},{"fullName":"HSUIFilePicker.allowedFileTypes(types)","description":"Restrict to specific file types","url":"HSUIFilePicker.html#allowedFileTypes","kind":"method"},{"fullName":"HSUIFilePicker.resolvesAliases(value)","description":"Set whether to resolve symbolic links","url":"HSUIFilePicker.html#resolvesAliases","kind":"method"},{"fullName":"HSUIFilePicker.onSelection(callback)","description":"Set the callback for file selection","url":"HSUIFilePicker.html#onSelection","kind":"method"},{"fullName":"HSUIFilePicker.show()","description":"Show the file picker dialog","url":"HSUIFilePicker.html#show","kind":"method"},{"fullName":"HSUITextPrompt","description":"# HSUITextPrompt A modal dialog with text input Shows a blocking dialog with a text input field. The callback receives both the button index and the entered text. ## Example ``javascript hs.ui.textPrompt(\"Enter your name\") .informativeText(\"Please provide your full name\") .defaultText(\"John Doe\") .buttons([\"OK\", \"Cancel\"]) .onButton((buttonIndex, text) => { if (buttonIndex === 0) { console.log(\"User entered: \" + text); } }) .show(); ``","url":"HSUITextPrompt.html","kind":"type"},{"fullName":"HSUITextPrompt.informativeText(text)","description":"Set additional informative text below the main message","url":"HSUITextPrompt.html#informativeText","kind":"method"},{"fullName":"HSUITextPrompt.defaultText(text)","description":"Set the default text in the input field","url":"HSUITextPrompt.html#defaultText","kind":"method"},{"fullName":"HSUITextPrompt.buttons(labels)","description":"Set custom button labels","url":"HSUITextPrompt.html#buttons","kind":"method"},{"fullName":"HSUITextPrompt.onButton(callback)","description":"Set the callback for button presses","url":"HSUITextPrompt.html#onButton","kind":"method"},{"fullName":"HSUITextPrompt.show()","description":"Show the prompt dialog","url":"HSUITextPrompt.html#show","kind":"method"},{"fullName":"UIWebView","description":"# hs.ui.webview A web browser element for embedding in hs.ui.window layouts Available on macOS 26.0 or later, hs.ui.webview() creates a web browser element backed by a SwiftUI WebView and WebPage. Embed it in any hs.ui.window using .webview(element) — it fills the available space and can sit alongside other elements in stacks. ``javascript const wv = hs.ui.webview() .toolbar([\"back\", \"forward\", \"reload\", \"url\"]) .loadURL(\"https://apple.com\")","url":"UIWebView.html","kind":"type"},{"fullName":"UIWebView.url","description":"The URL of the current page, or null if no page is loaded","url":"UIWebView.html#url","kind":"property"},{"fullName":"UIWebView.title","description":"The title of the current page","url":"UIWebView.html#title","kind":"property"},{"fullName":"UIWebView.isLoading","description":"Whether the web view is currently loading a page","url":"UIWebView.html#isLoading","kind":"property"},{"fullName":"UIWebView.estimatedProgress","description":"The estimated loading progress from 0.0 to 1.0","url":"UIWebView.html#estimatedProgress","kind":"property"},{"fullName":"UIWebView.canGoBack","description":"Whether the web view can navigate back in history","url":"UIWebView.html#canGoBack","kind":"property"},{"fullName":"UIWebView.canGoForward","description":"Whether the web view can navigate forward in history","url":"UIWebView.html#canGoForward","kind":"property"},{"fullName":"UIWebView.loadURL(urlString)","description":"Load a URL in the web view","url":"UIWebView.html#loadURL","kind":"method"},{"fullName":"UIWebView.loadHTML(html)","description":"Load an HTML string directly into the web view","url":"UIWebView.html#loadHTML","kind":"method"},{"fullName":"UIWebView.goBack()","description":"Navigate back in the browser history","url":"UIWebView.html#goBack","kind":"method"},{"fullName":"UIWebView.goForward()","description":"Navigate forward in the browser history","url":"UIWebView.html#goForward","kind":"method"},{"fullName":"UIWebView.reload()","description":"Reload the current page","url":"UIWebView.html#reload","kind":"method"},{"fullName":"UIWebView.stopLoading()","description":"Stop loading the current page","url":"UIWebView.html#stopLoading","kind":"method"},{"fullName":"UIWebView.userAgent(ua)","description":"Set a custom User-Agent string for HTTP requests","url":"UIWebView.html#userAgent","kind":"method"},{"fullName":"UIWebView.inspectable(value)","description":"Enable or disable the Safari Web Inspector for this web view When enabled, the web view appears in Safari → Develop menu.","url":"UIWebView.html#inspectable","kind":"method"},{"fullName":"UIWebView.toolbar(items)","description":"Configure the toolbar with a list of standard and custom items The toolbar renders above the web view. Each element of the array is either a string naming a standard control or a dictionary describing a custom button. An empty array (or omitting this call) hides the toolbar. Standard string items: \"back\", \"forward\", \"reload\", \"url\", \"spacer\".","url":"UIWebView.html#toolbar","kind":"method"},{"fullName":"UIWebView.backForwardGestures(enabled)","description":"Enable or disable the macOS back/forward trackpad swipe gestures Gestures are enabled by default. Pass false to disable them.","url":"UIWebView.html#backForwardGestures","kind":"method"},{"fullName":"UIWebView.magnificationGestures(enabled)","description":"Enable or disable the trackpad pinch-to-zoom magnification gesture The gesture is enabled by default. Pass false to disable it.","url":"UIWebView.html#magnificationGestures","kind":"method"},{"fullName":"UIWebView.linkPreviews(enabled)","description":"Enable or disable link preview popovers shown on force-click Link previews are enabled by default. Pass false to disable them.","url":"UIWebView.html#linkPreviews","kind":"method"},{"fullName":"UIWebView.contentBackground(visible)","description":"Control whether the web page background is visible Pass false to make the web view background transparent. Enabled (visible) by default.","url":"UIWebView.html#contentBackground","kind":"method"},{"fullName":"UIWebView.onLoadChange(callback)","description":"Register a callback that fires when loading state or progress changes Called whenever isLoading, url, title, or estimatedProgress changes.","url":"UIWebView.html#onLoadChange","kind":"method"},{"fullName":"UIWebView.onNavigate(callback)","description":"Register a callback that fires when navigation to a new page completes","url":"UIWebView.html#onNavigate","kind":"method"},{"fullName":"UIWebView.onTitleChange(callback)","description":"Register a callback that fires when the page title changes","url":"UIWebView.html#onTitleChange","kind":"method"},{"fullName":"UIWebView.onNavigationDecision(callback)","description":"Register a callback that controls whether navigation is allowed Called before each navigation. Return true to allow or false to block.","url":"UIWebView.html#onNavigationDecision","kind":"method"},{"fullName":"UIWebView.execJS(script)","description":"Execute JavaScript in the web page without capturing the result","url":"UIWebView.html#execJS","kind":"method"},{"fullName":"UIWebView.evalJSResult(script, callback)","description":"Execute JavaScript in the web page and deliver the result to a callback The JavaScript method name is evalJSResult — it derives from the internal Objective-C selector evalJS:result:.","url":"UIWebView.html#evalJSResult","kind":"method"},{"fullName":"HSWindow","description":"Object representing a window. You should not instantiate these directly, but rather, use the methods in hs.window to create them for you. Note that this type uses private macOS APIs","url":"HSWindow.html","kind":"type"},{"fullName":"HSWindow.title","description":"The window's title","url":"HSWindow.html#title","kind":"property"},{"fullName":"HSWindow.application","description":"The application that owns this window","url":"HSWindow.html#application","kind":"property"},{"fullName":"HSWindow.pid","description":"The process ID of the application that owns this window","url":"HSWindow.html#pid","kind":"property"},{"fullName":"HSWindow.id","description":"The window's underlying ID. A value of 0 or -1 likely means no window ID could be determined.","url":"HSWindow.html#id","kind":"property"},{"fullName":"HSWindow.isMinimized","description":"Whether the window is minimized","url":"HSWindow.html#isMinimized","kind":"property"},{"fullName":"HSWindow.isVisible","description":"Whether the window is visible (not minimized or hidden)","url":"HSWindow.html#isVisible","kind":"property"},{"fullName":"HSWindow.isFocused","description":"Whether the window is focused","url":"HSWindow.html#isFocused","kind":"property"},{"fullName":"HSWindow.isFullscreen","description":"Whether the window is fullscreen","url":"HSWindow.html#isFullscreen","kind":"property"},{"fullName":"HSWindow.isStandard","description":"Whether the window is standard (has a titlebar)","url":"HSWindow.html#isStandard","kind":"property"},{"fullName":"HSWindow.position","description":"The window's position on screen {x: Int, y: Int}","url":"HSWindow.html#position","kind":"property"},{"fullName":"HSWindow.size","description":"The window's size {w: Int, h: Int}","url":"HSWindow.html#size","kind":"property"},{"fullName":"HSWindow.frame","description":"The window's frame {x: Int, y: Int, w: Int, h: Int}","url":"HSWindow.html#frame","kind":"property"},{"fullName":"HSWindow.screen","description":"The screen that contains the largest portion of this window.","url":"HSWindow.html#screen","kind":"property"},{"fullName":"HSWindow.focus()","description":"Focus this window","url":"HSWindow.html#focus","kind":"method"},{"fullName":"HSWindow.minimize()","description":"Minimize this window","url":"HSWindow.html#minimize","kind":"method"},{"fullName":"HSWindow.unminimize()","description":"Unminimize this window","url":"HSWindow.html#unminimize","kind":"method"},{"fullName":"HSWindow.raise()","description":"Raise this window to the front","url":"HSWindow.html#raise","kind":"method"},{"fullName":"HSWindow.toggleFullscreen()","description":"Toggle fullscreen mode","url":"HSWindow.html#toggleFullscreen","kind":"method"},{"fullName":"HSWindow.close()","description":"Close this window","url":"HSWindow.html#close","kind":"method"},{"fullName":"HSWindow.centerOnScreen()","description":"Center the window on the screen","url":"HSWindow.html#centerOnScreen","kind":"method"},{"fullName":"HSWindow.axElement()","description":"Get the underlying AXElement","url":"HSWindow.html#axElement","kind":"method"},{"fullName":"HSColor","description":"Bridge type for working with colors in JavaScript","url":"HSColor.html","kind":"type"},{"fullName":"HSColor.rgb(r, g, b, a)","description":"Create a color from RGB values","url":"HSColor.html#rgb","kind":"method"},{"fullName":"HSColor.hex(hex)","description":"Create a color from a hex string","url":"HSColor.html#hex","kind":"method"},{"fullName":"HSColor.named(name)","description":"Create a color from a named system color","url":"HSColor.html#named","kind":"method"},{"fullName":"HSColor.set(value)","description":"Update this color's value. If this color is bound to a UI element, the canvas re-renders automatically.","url":"HSColor.html#set","kind":"method"},{"fullName":"HSFont","description":"This is a JavaScript object used to represent macOS fonts. It includes a variety of static methods that can instantiate the various font sizes commonly used with UI elements, and also includes static methods for instantiating the system font at various sizes/weights, or any custom font available on the system.","url":"HSFont.html","kind":"type"},{"fullName":"HSFont.body()","description":"Body text style","url":"HSFont.html#body","kind":"method"},{"fullName":"HSFont.callout()","description":"Callout text style","url":"HSFont.html#callout","kind":"method"},{"fullName":"HSFont.caption()","description":"Caption text style","url":"HSFont.html#caption","kind":"method"},{"fullName":"HSFont.caption2()","description":"Caption2 text style","url":"HSFont.html#caption2","kind":"method"},{"fullName":"HSFont.footnote()","description":"Footnote text style","url":"HSFont.html#footnote","kind":"method"},{"fullName":"HSFont.headline()","description":"Headline text style","url":"HSFont.html#headline","kind":"method"},{"fullName":"HSFont.largeTitle()","description":"Large Title text style","url":"HSFont.html#largeTitle","kind":"method"},{"fullName":"HSFont.subheadline()","description":"Sub-headline text style","url":"HSFont.html#subheadline","kind":"method"},{"fullName":"HSFont.title()","description":"Title text style","url":"HSFont.html#title","kind":"method"},{"fullName":"HSFont.title2()","description":"Title2 text style","url":"HSFont.html#title2","kind":"method"},{"fullName":"HSFont.title3()","description":"Title3 text style","url":"HSFont.html#title3","kind":"method"},{"fullName":"HSFont.system(size)","description":"The system font in a custom size","url":"HSFont.html#system","kind":"method"},{"fullName":"HSFont.system(size, weight)","description":"The system font in a custom size with a choice of weights","url":"HSFont.html#system","kind":"method"},{"fullName":"HSFont.custom(name, size)","description":"A font present on the system at a given size","url":"HSFont.html#custom","kind":"method"},{"fullName":"HSImage","description":"Bridge type for working with images in JavaScript HSImage provides a comprehensive API for loading, manipulating, and saving images. It supports various image sources including files, system icons, app bundles, and URLs. ## Loading Images ``javascript // Load from file const img = HSImage.fromPath(\"/path/to/image.png\")","url":"HSImage.html","kind":"type"},{"fullName":"HSImage.size","description":"The size of the image. Setting this resizes the image in place to the exact dimensions.","url":"HSImage.html#size","kind":"property"},{"fullName":"HSImage.name","description":"The name of the image, or null if not set.","url":"HSImage.html#name","kind":"property"},{"fullName":"HSImage.template","description":"Whether the image is a template image. Template images are tinted by the system to match the appearance context (e.g. menu bar icons).","url":"HSImage.html#template","kind":"property"},{"fullName":"HSImage.fromPath(path)","description":"Load an image from a file path","url":"HSImage.html#fromPath","kind":"method"},{"fullName":"HSImage.fromName(name)","description":"Load a system image by name","url":"HSImage.html#fromName","kind":"method"},{"fullName":"HSImage.fromSymbol(name)","description":"Load a system symbol by name","url":"HSImage.html#fromSymbol","kind":"method"},{"fullName":"HSImage.fromAppBundle(bundleID, withFallbackSymbol)","description":"Load an app's icon by bundle identifier","url":"HSImage.html#fromAppBundle","kind":"method"},{"fullName":"HSImage.iconForFile(path)","description":"Get the icon for a file","url":"HSImage.html#iconForFile","kind":"method"},{"fullName":"HSImage.iconForFileType(fileType)","description":"Get the icon for a file type","url":"HSImage.html#iconForFileType","kind":"method"},{"fullName":"HSImage.fromURL(url)","description":"Load an image from a URL (asynchronous)","url":"HSImage.html#fromURL","kind":"method"},{"fullName":"HSImage.copyImage()","description":"Create a copy of the image","url":"HSImage.html#copyImage","kind":"method"},{"fullName":"HSImage.croppedCopy(rect)","description":"Create a cropped copy of the image","url":"HSImage.html#croppedCopy","kind":"method"},{"fullName":"HSImage.saveToFile(path)","description":"Save the image to a file","url":"HSImage.html#saveToFile","kind":"method"},{"fullName":"HSImage.set(value)","description":"Replace this image's content. If this image is bound to a UI element, the canvas re-renders automatically.","url":"HSImage.html#set","kind":"method"},{"fullName":"HSPoint","description":"This is a JavaScript object used to represent coordinates, or \"points\", as used in various places throughout Hammerspoon's API, particularly where dealing with positions on a screen. Behind the scenes it is a wrapper for the CGPoint type in Swift/ObjectiveC.","url":"HSPoint.html","kind":"type"},{"fullName":"HSPoint.x","description":"A coordinate for the x-axis position of this point","url":"HSPoint.html#x","kind":"property"},{"fullName":"HSPoint.y","description":"A coordinate for the y-axis position of this point","url":"HSPoint.html#y","kind":"property"},{"fullName":"HSRect","description":"This is a JavaScript object used to represent a rectangle, as used in various places throughout Hammerspoon's API, particularly where dealing with portions of a display. Behind the scenes it is a wrapper for the CGRect type in Swift/ObjectiveC.","url":"HSRect.html","kind":"type"},{"fullName":"HSRect.x","description":"An x-axis coordinate for the top-left point of the rectangle","url":"HSRect.html#x","kind":"property"},{"fullName":"HSRect.y","description":"A y-axis coordinate for the top-left point of the rectangle","url":"HSRect.html#y","kind":"property"},{"fullName":"HSRect.w","description":"The width of the rectangle","url":"HSRect.html#w","kind":"property"},{"fullName":"HSRect.h","description":"The height of the rectangle","url":"HSRect.html#h","kind":"property"},{"fullName":"HSRect.origin","description":"The \"origin\" of the rectangle, ie the coordinates of its top left corner, as an HSPoint object","url":"HSRect.html#origin","kind":"property"},{"fullName":"HSRect.size","description":"The size of the rectangle, ie its width and height, as an HSSize object","url":"HSRect.html#size","kind":"property"},{"fullName":"HSSize","description":"This is a JavaScript object used to represent the size of a rectangle, as used in various places throughout Hammerspoon's API, particularly where dealing with portions of a display. Behind the scenes it is a wrapper for the CGSize type in Swift/ObjectiveC.","url":"HSSize.html","kind":"type"},{"fullName":"HSSize.w","description":"The width of the rectangle","url":"HSSize.html#w","kind":"property"},{"fullName":"HSSize.h","description":"The height of the rectangle","url":"HSSize.html#h","kind":"property"},{"fullName":"HSString","description":"A reactive string container. Pass to .text() to get automatic re-renders when .set() is called from JavaScript.","url":"HSString.html","kind":"type"},{"fullName":"HSString.value","description":"The current string value","url":"HSString.html#value","kind":"property"},{"fullName":"HSString.set(newValue)","description":"Update the string value, triggering a re-render if bound to a UI element","url":"HSString.html#set","kind":"method"}]; // Load navigation links into left sidebar function loadNavigation(currentPage) { diff --git a/docs/ts/html/assets/navigation.js b/docs/ts/html/assets/navigation.js index 5183c603..0c1bf271 100644 --- a/docs/ts/html/assets/navigation.js +++ b/docs/ts/html/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "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" \ No newline at end of file +window.navigationData = "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" \ No newline at end of file diff --git a/docs/ts/html/assets/search.js b/docs/ts/html/assets/search.js index 85e4b0df..bd43fe13 100644 --- a/docs/ts/html/assets/search.js +++ b/docs/ts/html/assets/search.js @@ -1 +1 @@ -window.searchData = "eJy0vVuT2ziWrv1fPLcVNUkcyb5znaZqpqrL23Z37S86JiaUEjOTZUnUkFLa7on57x8BUBKw+IKESO2b7nJqcb0guXB8FsD/edPUn9s3f/nH/7z5VO03b/4ivnmzX+3KN395s673bb0t33zz5tRsu3/v6s1pW7b/2v/925fjbtv9uN6u2rbsXLx587/fnL2oq5tN+Xh6vjh5Ou3Xx6rzcHFjfwfOvnlzWDXl/uiVBPovm6ZuRvzb3xf4r/ZP9Yh78/MC79t67Nl0vy7w/XnV7Eecm59v9X51/tIOAuOlHY2J67WrwyF4qp6D/qfxcnXaV7ec+X7/av7r7Pd11VSrR+K5N5pSONtjpcdTtd2M61iTpSr7zbb8ZdNZV09V2UwJhtb30H63Or6kqBq7ZXpdrD1Vzz9UEzd5MbuH2vTdXe2W6h2+NtXzy/Gv9bFaT0QoMV6mvKnaw3b1dbpeeIbLFHfVvtqddr9/+HvZtF2LMy5LrZdpN2Vbn5p1Qtz6lss0X1Nu83X23QXN5rZar46+WNh0nn++ofn0+ovVZvPH6rh+KVF3SgSutim3dCk21H1q6t27X36YFu0N76K4P+7q9pik6UyXq25XncjL781P9frUTisH5svVd+Z1Vfvn71w3kfC46RX3K0PQGk3qpzZJE9rl/vTdqvn98z4lvn3r5dqHrpH5qW7SHz254G4l+Knalh+/HhIePrngPiVob34I7d2fQnvzY2jv+hyacle/lskNbWB+B/XTft9VqbdXu4SWCFw0syReZ3PaVPWmfPVHQ35ndv15Xmf2X7vVp/IH6+DHXXU8Rp+1JzS8Zvo2vduY16l6+rd0qpO6222C4HZ7F6Vf9ofT0T24WDiFqv4FdynB76fjjUUIrlhehk35tDptjz8+PZXr3ut0McBFdyuJ94iTC+Jdc7dy+M85uSD+RctL8tT9wfn67uvI0MMrBr3ivmX4W7T3ixThbymd31QJUjoeT//Gjgeqe1X0C2zlv8xb6NnXZonD9S6mV77W+HDy9eXbgeX0nXyZ2ZB/uan9jqlcu80ft+XO2EfVBqazVUt3/dvju7oaUQzNZquZyP7u63t/bZkqXU0WqnysjpMy1ma+jpmelZuptxWazVY7NN2T/7kqm1WzfvkaVQvNZqulNBlfbm0pIlrt1/ZY7v6oNuXUoxxYztb83P2h/jylF1jdpnWVeqz3f9an60P0WsH+p3lNYVs2ptEdaQXP7n3Lybs4FzfSFL6WzbFqIxXrLHgxW6a2bsrVsfxQmlAeF/Qtl2nuy+Pnuvn0wT2yyIDyLEuMlym7ypRyt77lMs32WB/e9i+rm+eNyxLjGcreq+3+r1mhOuF+WTD1+946GJ369RpD88l76ss9a5zQq94wVhhVi03zzjIJM7wx/66HjA+ae5mr2R3UosPjQCxlTDymldC39Xq39W8DTS/cX+q6LWEf0P80L+Bduxe5h96xs5kufV9EVPxNvYbQ1/x9JnE4VP/+4fe/4pJbt73FZLlt2aDGcxnp2a3/7tcFvv9sf+h+C2DTUOJqtECpfak/j2iYnxd4P6bcx3H2fXgTjdfO5rg6oDA6/zZvHGRyFU4xxnlx3VtN3sClnFCr7LqJCSFjslTF/DoyrrtqXQwXKnYvw2YO/LRdPU+JBrZzdG/oMi+iN3Sa44qP3R9+ro+fysgU6qJ4NVyo2BV6/em3upsDfnc6HqPL7tdIpfZL9U+NMf2tf22T8sR8ofqmPnUR9P22Wn/6Zd+NsF5XkWHLpQDgiruU4dfy6Wi9JulfrBdqd/Hzvjx0PfAP5XY1FXOh8b2UE5/7wH65/odjU3+KDE98XWd3L72pCL8aLlTcJkbU9k6xZKYr/1F+/fE1umZxbaQ90zuq/lEdX76vN1OvFF1yh1LYRjH17q/Gd1D+sG7q7faPl7LcpurTS5aWotps+lZxSvxquVTTPMJfa5J4FFH1bRfqumlXUi/tm95FNW04ctvEcELXJPylvNir4ULF9hqaE5Ke5RxNb34P549Pc2ePm83f6203nB99W513ajh5E0/R+eqh3G/iOvbn+d6Px6Z6PB1jXZdRuJjMVlm/bKr4o7K/zvddHyJV1bjufpzv2Y1Hfxgr+sVktsqm3JbHMj4P7lSuJvNVQEruQOaGbNyYTvlnuT66wI/qeDbzdb5U7TEes+7n2d6fqm35t4+/RN33v8/2/1Lvyi5musdQN/HgDaxma1XttJJns0DH5KuNSJifF3h/X642ZklgROFsskDlw9fdttpH+kMr0lss0PijqY4Td3I2ma0yehOLyr+tYinM1nNC0vKY5/dl16S21Wv84QRWs7V2n8Z6JPvrfN/1SPHNj7M92wTZpt59V9efdqsm/oap4SLFj/Xbx7ZrrmPL/b3e1WyhWtLdXc1mqzVdcxHVMD8u8vxrtR8ZVF0sFmmM1vKzwQIFE6xpw11gO193N1Y37a+zfbcT7Xu7sHU/+qvY1PkxZdk66rncHepm1Xyd7s6HpvNV61MsJ8AImV9n++58mjZqdOjr2czWebVRGX8t/e+z/X/uOut402h/ne37i5l9/VsMJ3buzwbLFH4d69QvFss03pejHaNns0znw9TT+nDr0/IG7qv2Gqv+HuTu7/MWFB5XbanED+U6urZpfftmk4W3pRxR+3GfpObMFqi97Fbr336QI0K9xUKNDz+/zSZEjMlyFSbVtE5ntFxJZmxaqTNaoLTbjL2Z7tcFvtuX1dgbMT8v8z7+JpzBMoXxN+AMblXwVwCCJWa/KUlaUY4j5kihnVdjMF1oV7aowodDuZ5UMUaLlMYSjHqdxPyiaZXf6k0MUgZS1m6R3nN5/I/yq6FSv3kZKUgxsFyqeWbqCaKe6e2qXoAfjzDjxvx9ZsZZvTcZoD931/64P1bHKjaksxLAevp2TJkjHP99+d+nMjZIsooXmwU6pe1yf6qb/3MqYwN8KxYaLlCMpqpZmZRUtbjv+lDu/ygfP9TrT6Mqgd0CvUN0d72VOaTsqB/xfhp1flriu/P6btXEFrStwNnkVpWwSpqEfJwNev31/gmhnu/UNvtaVnQr1WGN7qH787xMvqo185ty72eiBzloxrNnNFl+U0C8/Ltvj6vt9rtqv4pVcKvlmy1Qa52HX5y7MjI6cHdHTOerdg6aSF0xSvbnJd7rSCfmnNfT/VbU92mf+H6I4Y2KQeqQacghoz7/Ni+kd15XH4Tyxe0uoYe/lG9WEuVF6oYkynHFHrj+uvpax5rji2hgex/d38rjSx2pRFTX2d5H94M9Nyi2R4Eqn60Xam/tg4v0SRfN3mqh1s4+rCmt3mqhVkK6zUXxtnSbcd22TIvbi91yvaR4vdgt10uMU89yjqYXojRFzGs+t4kpYfOatov3G5q2S2mx4ql7B031T2vy4bg6xg5sukoPr1hYhk03wFntY4cmXITPZgvVonOPi1DK/GNcY1vXn06Ht5tNU7ZTzzOwvYvueAojEU7OYRxXTmjeLsK3NW/juv1e3/bHvRlqRBqdizKxXqp92jfRvcFXTWe1XKudDFxnNEfJ7xP3p8cVnKz1P91/pnZ2nDhNOxcRFb/fooyK3/80b2DblWz9snqsttXx68iuobPGwHzyps4Fj/ULpnWIrT2dVS9my9TcWaCnxgbJuX2YkMbX3LEcH7rxyWi7BkviXXXPshzrJhLKuBTG/o76o80sLEFqYztahspslHlaRY8JOCtf7ZbpHaJb9M9Kh5RVkXGNptrZ9Ye+yBN6xHqZdtBI1M3ocAE2LJdr/l+U490qlg8zXhZz3V3L83PdHuMpxJHCnC+6X0nsS9/H+mBUjPMV9yvDr9X+k2nPItgIFeJyydJStPU2lkhx1bVGM5S8DtycYwUZpfvl/qOP3m/i4KMv38gg+O12+0O5rV7LJjYe7RWH5vdRf1fuN/Gmk2j3xouU43v2e7WkXfsDBY/prOGAtPvzvHBoynX9vK/+WX4sv0QqtPEdmE2W3xQyMnY/HOrmWG5+Xe2fT6vnWP9pJIe2N+p6D61dteumOhzhozv/OO8B/lf5pVxHc3Ovzs920zdxKeyo3oev+0gWwFDT2C7VNUfPleQpRmQ90zuqmjzE+BYHqH6+5I6lSHnsxPzO6jOeg3/Z0tL8uXqllSlSgKvl/TRTb354xf3KkBICofV9tW9/Bovfv79FoD2Wj/WquXboXlt6/XXe2kI3Vts/l9/Xp33ksBVPwLOdvCev1FD3s5sUDs5LiGkT+3n6N6x2e9I3rHdPqa635Wpa0Fot1npZtfHT1/2wcXaL9czuix9Wx9Wk4NnwLoo/f/zt1yRFY3gXxV923cgoSdJa3kXz/cefkhQ7u7vofTg20UE8kXSmd1H92/u0V9nZ3UFvkhkEqrdQgyntY3DcVEzzmHTW1JSW3YyRVC0vlvfRTKqYF8v7aKZVzavpfVR/fzTbu6dfqG98H+WUZuFseB/FxIbBs72PbkrTcDacp+gNuMpmV7VtwB38Edf155nrQebQsbfrddk5cetkkVvzhIbXTN+ldxvxcrgjWRML4IzvpDxOVAbaySglTf23at3Uh5d6H2svqP71gjuV4K/eofmxxoMWIrjmTuX4sG7Kcv++XNdNfOVuUBJy1fKyNC6V/MZ6ga66W1lS60Zgfjf19PpBLrhbCW6pI4NL7laKG+sJuupuZbm5ruDrZpbHz/v/jHPa7Q9zM8K/f1k1z9GEcOf6ajV9E7aQsezz+vM78/tv/r5MqOdbLtHsnum6s/NHiEDvarVIy/zkEv5Gxa5mS9SO3aRkt9qafLhROd/uZr1w7eS7lTnC/ev4/MmKDowXKruDDpN0fdNFqttt/fnDtiwjWfi94MVqidaje1a/4O9hX8Q8syVqffr02+7CZqx9tZoD4yXKm7K7qinfdiKv8Z7e6hLTJapVa1/Qu8YeoBdDpOeWJ7RdorutzyOmMcWr1RKtgyvwZLz6dkv03NpIeoOA7JfrpzYLQ+sl2nZjj3tl7ep1XJnaLtK1H+eZfMWe2c1qnlgYuN5oo00K1mijioveO035pkZfMry/YlVFKlsvYAwWKfQJWaMivc3tOkGCQ3Nc+9tS/Ddw/nHeS4gfbXZ1nHTC2bWQUMfsd53SMTZLdZrTpExnMkvFeyH1aQ9ZnP1h3ot4GiWMzvFTKk90BYQ65v8ivZ4TsQZLFPo2xxhERhNOyLe7Wc+TO9THrTmsF76Q84/zZkSXc2DxoPrq/WI4fSOX4kLFdl0fJtWs0SylxKS0q1RiXtqEVjvynS3vttK+sYW0PLSyamH+vfn7vCBozQx+H5vHWb9nk8my29JBlY/dL9+dqu3GG0MMhTyrW7X8KQbRCd6H1XlcrDEWXlYiMbLiCp2V2bQdGURYjbPJApWut3jbRrNPrMrZZIFK+1LGRkMuwMzvt/r3KkW1w6tF9oeZw7f+5MuPVSw52jn37abvwBb09oCySqkRFdfYrL5GuiynYH5f5L9++xT9Tl4v4UwWqkTGdBeJ6fHcqP9u9hQb9p4lrMkylb/tj1WsUvQq1mSZyh8v0VHXWcWaLFF5qU+xTwH1NdAYLFEwu+q2U1XxYrREaVft42fnO53eZIlKW67rblz4oep61R8PdWzw4PQGxkuUT218Uu3knMUSjc+r6jgZ3RejpUqTEX4xWqRUlp9Go8Ia3KzgdWLNat9uo3vfvZ/ndWhtaXlL5BY8773h9K14BY4tHkV3vAeCafvcp/UStwIE2rdvCcDl8GpYhd7fqZq7jFTGTt7pXNpfJ0vclQj3DtVqW0cgX+fc/Tzbu/mkwrtq/Sk2IOgUriazVdqRhJ1OoU3L0Yl5P5Zfju+aehdLTe8UriazVT6Xj69VGdnl00n0v8/3X5lPj8fd259v8+6Fe7Mtg89Y+UHf/zZvZmpODPu+m+A8rrzPGQWTRs//1XT6Rs4lhqq7VbU91om6ofEcZX/eWu0jS1cXvaTTPsdVnsvj2+3259V+07Ud7U9182H9UsYGVhfhyFXLy/JD+bQ6bY+95+lShPYL9c2SbDTz7qLaW91Hy3zC7ruTKXya6tV+oX5747Me2M/R98edj7CFaB9n9osT+xuM4xs2NpjiYZ3jcdV52PxQ2sNNRsRCw/mKCZnbRu+2lO1QLdo1eG8mrVeIsq8/7OWR59X7vppNlr8v5xjkT1EMTZepfl1vyyRNz3CRovti/cfqGGs7ekHPbplevT615eaPkdHDWdG3XKS5W32pdtU/x2/wbLRMqas9H2vzad6fV9uncb3A9A6q7836fqLsxXaRbt1szB74lHgNTRepvlZt9ZhWS0LTRarut7fHd3W1j4zbe9HA8g6aZmD09hBZXQk0e8t7aP6+H8u8CVXPtstaPrN97/vOfx1riHyLmXsItnVbTmhcLWZq1NttuT7+26p5jG6rCW3m6ZiR3OiteAbzFJpyW8e+fOV+u8FvxvKL458/dEG6rUiidu/kX4NfgcLVp8y8HbldwY7NyXzFKMHjv4TmuPxhMb1beWCjg5IR2c7688V6geqjHbt752eOaDrbanMPxeAbTJOaB2e9QBUPFkaE+wsuA9AF2lVrcyfLFNmqXZ1tFyn+XG02ZUqV6BRfzraLFN+f9sFp5qOSzcV4geYnf0FiRK63W6BkctXSQ8dY3yNuDlXS7R2W1shjMGQfUTobLtCKDLlGRPsr5rZ27EFc+wtbt3yOPdbCXm2XKH75cVvu/PXHMckv5cV4gaaZYP1W7k+/HMvdd+EXmMcavO4qc7pm1V31+HXvrrpbKVLb+7AUs9r9QSluaPQ7y5k1N1A1X7Xpbz0pxjv7800vjPDOU/rtdsb3uNuu/0iKsN5ugdKnysvTGW3xt/HRZLJSkSpVLNNqSzOGv73GuuvuWWdpSVJrLS3J8np72qdG1cXyxl4pnEacNlXtlkaR5vXXe00jiMfUaYRXzNg04nVVbQ0J+rDaHbbl+5WfLTJSgMt1rb2u6a9bUJLH1TY42X1E/Gq6QA+PlqjU+GApQWV/OB2/f1nt9+U26cHaC9bXC5Zq/3byN05NCe9666Wq7kPLybKvZ/Mluu0ve/8TWGOabdWbLtL7/XRMFqzPtgsUd6mv8g5vcR/pVKjUVCcyreSezC1VxF1xnzrSXpq9FOVrY7dM1SbdmEyd4MivEeHLBUd3wQLtU1rDd1ra8r0mNwEza384cRoC1LHea7P5fLFeoNoDONvwmLOYyB7ysQ7cXWnboU13ZXu+cnlpXLM0qziuZt2rPFX4WNK7v2sBbq/dQQlq8ihuaF7uVgYMwEf03QV3ic+2PH4/O0S7i/9fROm1THMC9Vqo+8bqNT/kx6enbnKSPLg3Jdq4K0t75eZ85V1K497bjMK4d3bXsvTva0Zh+nc1rzRk6vV/R1bIzr/da9oV+EuddF0KGOkY+0W7H/qzhyMoKpTur9kE18wuwVMTGd2Fomez2TpVS7+1FNWq2vJiukDvJ4dhUvSeLqaz9XrbSbGL3XwlPGgjMuNDtkmNuq3SotGznK3W1BgihEq91WyV1k++iar0VvNVTo9pt3M1nK0VpS+h0iR7mdJ5XW1PCTpns1t0Boyl3ps1TDg4C9Wc8b43nq953gCeKnu2v5/y39Me78V+8XNev1TbzdtuPLEpvyR0dcZ61Q0inPUy1QaTZaDYjHPlKbWqfXt+Xh/K49H0Jyk9weUht9eLZpfhUDZPdbN7u05sSp35aj2jPaXDtLc3Bld3yaL4Cgdm39X7P7uB+Ifw9ICrePD7nQZoQ5+Jg7SwsNEVYjP3eargtA1IB/bLlPfr7akb7L0ry+Zjbf43sQT9dYfuimN9KGeVZABEv2vqz62pFz/UJlcBNZigLObKx/OVm8uVi0vzvnyuujdsAc3NBWq8i+9Ypg/9x0LTC9Jer1ikHnxsflS1t7w5LnElbyKTwNDg3tW88VasbqvnzSgEG3wzc1zbt1+m7GIwUfZivEzzpW6PkeV9pOqZL9NNa0495dva03HtmxpUvwyzWtTRstzw7O/y3A02SNTrTZfpHb8c3dG5iaKdfXO2X6iMaQoUHecoUb2g8d3V+yq9xbpaL1Ol31ccV71aL1Od6mg8ydSeZlLvN/fEcJpoTHnnX3R7PAXdHTlS/CoePTx8TvfmOUvs1vpyjZDwv7UoQHwlA8FP7VhgjKtEmjFfYqL5GvdvamgktcnXMGaLdDAP9SXGUejAezqX9EWSkOS41np1OJ4a8lmVSJg506o3nac3RbZ8wVSoNXxXYYV8qesWi7lf7lUlPW+pdbIvWmzV3y5v9yTlp7r5Pyf/VKaIcr8m7i56qpv/7i+aWYbREVggnDT0mlJr/+5ysSfF2teL4Uytev8zzv8LhOqp3L9JlV/2r6stbjBCoepiOFvLRsj39iN+03o2MtZn49maH2xm5rRce7abr/QCk46pzstotvGEymG7WpcvdXB8YkQqNJ2p998pdXphHXbnbn44PQbfI45oOeP29Hh0xrM1zdsuN++nX9nZtFny3sa6fl8spe8fV+obnvd4c0kg1ps247tKJvQ+VxuYIh0onY3SNVLy6wOJm9tB0vE/ddOKl84qsugVaPXW64v1TNU2qW2a0TIBFRvr39f7Y3fV5A16Mb++XjJb/5j4XE0qzOJnmtAK394Gh0O2eouHWObv9xquXXylDtZsoeKvYFzDGczy/QLpm+f7ZRS4jfo2/weHJlfvZ5NZ/pvnx3HvziDVdxgm9hsPH1dojeH8052CJXCXGC+X0s0ZWYeCSUPrKT1zyn+5/32/RcONUM+Z1s70Bj1CVr+35/Wi8CK3164vlvPV4nlDVG06bWhKzbS49Hy0mJ5pc6+2sxXNt0WmtXqr+SpwxY6KjK7VoTiE1fbH4NC8odqPkYPzllTgq88ba/GP5FwvcuDA8Vjv/3raPY5WZk/cXbE/X7FIvZvCNatuMNGg7h/duG+/SPlpu3pOFD2bLtL7VH79voYjVaDYGa/r0SFrkuaWfqRxVNSzXqTarD7/lP5wO+u7PN+uHa6322r//EO5Pa7+b5r45aKNuWhsJDKjDP/fnDKk9FqjZYhAISA8wYSS1SJT14jixAQ2pho09ZuT27OaKOubL9I91G1ao/8vveXNzxZ2Nj/Xx65BGBF2BnfubjynN/Y3fXljTX4/oHhncwrGxjxBCfqrDper7lOK991kdnV7MZrrZTeXIwzlqo3k7SH5q/UyVTeKTBS9GC/TTBnl+rK3jHWH7zqoSD/VcLBm/nynSnNxlVhVbIkiD+qx3qDKfpXoDeb4NvFbw0283h1cbOYpxPZ4+ApTezoSFFiKBJurcepmCrtxhbPJHP9PdX3c17ADuyp4RnM0XsrVphtXjGt4RnM0tqvmufwYydG/qlizqRz9MZ329Jh0O6HdLCX75bdxkbPJHP+xDQ1X90uek712vGZcTGb759P+ebr/sKmOjnXuOsa5fWyzdEwzbyyzeAwzc+wyMWYpuwdWT7ykf7lazVSJjoxuGxHNHAndNAKaP/K5dcQzMdL5+ePHdybLC67lXH+8VzUKHaZWpWsZ5ywvU9GkBWaomRrURDAhsCfVut7wl/2xbJ5WMK2cSprO0zNfpBuZrgPJial6kto7nI0L1CaScafVWvuVi/rzD1VTmhD8+mvVHnEyJZU3W4PMpZvzpdvLpYvK0+ddppXg8WK8SHNkcR+IJizvJ6leHvovkR13QPvytKuJfXdpJajXJ7Nj6303ak7U769o3BWL1G+pze29anPn6LfVl++66eAHvPEXKO9WX8z8cWIPcJJ2YkvS3qEl6Xy86679jNPsgeLhar1MNa39au/Tfn389cNPTb179x/ff8jQKB7IHret+fT24dO6zcZG9Un6f5SPH+r1p1sbkc/lY2svu09rEsGFA+EJYJiiBJHhUGgUGuLxTDAsi+Uo27/faTB29ZU4DnOFui3d3ROZqNOj3iPnFHjeJ9qnUe/d5PywxXTAU/CsUlXCJaL68HX6vf6LMZvKOx/XaerDodx83/mZUHKGa2c4S6tdmY+W/FTBGZH/djq7Y/1UjU6KxpVg0pEvMZp0NOrbtIdvDwfyoS6oYkxXh8Pj2XS2XqQvJFI31pmBSuTEWaIycb7spMqHr7vHGp0kTHTas91sJf/zbVEZ8/NMjaprCX+qm+mANoZPdbMkoj2tyDGHWG8Cww5auqBj+bVn9vFdKcTiTp0N8prY7dAiRxrxTTcDM6feds/zmHxj/3K+6ul81cJSjK5EwBIkLUfE1cPV9Xj+BtROyOBIVB6fR0LxtMlkqn5kDIiVJwaCyZpwNBiRHB0SjkRXUH3NWeLfrZpfMHHwfr1TtaUeE6usX8zYmCuCNQaKU3QDayUu1Q3UptfqEvQiOwwGYhO7DBKUxvaQDeRS9pElaJqqvq3Wn0bq+0Da1HVzTUKFTyvBL2vYyiHhaj3awKXpGatEvZ0zXab3sa63xwo1L0jyeLFeoor3Ogz1xvc7ROp+0Iz9tTx+rptP33djmur51EyMSEas79TMTSkkNntjt3V7PtxkoRKy49JKdENPPlmotF59Xrn+o/yKkkRTyvTJXXrP8kRGHNOlmRh9zCoLHIkkFGV0VJIYz6hqv8Mcxfv1vlX34vG2qmqLGama/SlGKZpX0wV66/oEs87AHTrDBVpV+24VOQh2IFe1h9XESbBJivEv2gHJ6S/aJWi2ZdoD7e0WKUUQOtDqLReoTXcaV730ToIokhS6bo6MVniGwXm2XKB2WBk2kFTzrqaL9E7wOBigNn4iTIJW107gzz4MxC6WC9SSOnM/OG/ovEd1T7vdCu71H2peTG+sEajbeV+u1i+rx2pbHUfEfav7dkMDz7d1R0HxZ1f+YSHSG4FICW4PqmEhbgqupHKMj8BACdJGXonax9NICwXF3RV3U/9wjBz9NVGG9jhx+tdNJRkbeaISpIw4Y/UgrPK1WTaNLnj6P9+rklOXqbXbL+mcheOhcNKqcUSXVOY9HAUOFHvDJVqfq+PLplmhVYahnmd863MNwuT379///mhGXbFACQ3uFCrAaWKwkPJGwuWxmwNsUPuDhC/GyzQNgjJxB3OWIjd8vWCZ9hGf5oNUJ87ySdSL97JQc7qDjevScH3fDfy2kbt1v90vSD1/6fHZFzDy6OrrXUYC1Bcl1rNV4wHiq03HxoTKaFgESkkRMVQLguFdXcEZrP37nYLg6isxAFyhIg8IZXJ6CmNJm6N+0Wje8zs2fRj4DR7xe3xmkvnznR7wxVXi87UlijwGlMxx9T+WxDHmtW6qZ3jK9tX1xWSO/0j21tX7RPLWmG80mLg6Hhs9jHlFYXz1OhbFY15REF+9jsUw9RqE8Id1U8JPiLgf7hTGnrPEQO7LFVte3T1WneWv1fMLqoC+XG+67U1n6p2/yPxbvSlRxxQono13vfE8ze7aT92EJ5b15yv2plOZf+N6sQ+X+UJTXy2bUDhttz+lqHR2y5TgKaK+xOjpoeO+d/hgFd/7bvw4lXH/kWRY3//E2GDc/8inyHyNhO+Qjes09TE2a/J1PLN5Oid8yLSvcRo/ZXrgPzxl+rGtt6dj+bE2iTZoHTuo/L31sd721vNU7dUf67e9uwlVa32sV1freaq7qmnq5venqfi2ZvXTQp0PeP1nqDSx8DOutceD+6A+jY/sx/0fmvK1quF6XlCfrmbzdEwiyXTTY3JIbmx9qMrvsREd0Zkc1k0qvWuqyEo/kTpcDGdq7VeH9gVu1QqUrmbzdI71jyt4ao+vcqzL1eiBPVMaf60bmJkdiux7q7kqH+pTgkrbW81V+aNMeF6fy9ueFxni4hmE+fO9hrdnV6mDW1OiG2ZpV/+jj3rEK5rpXL2OzXSo1/DRmsVB5Nr8/V4P9+Ir9enaQsXWId0Hrj9WeJDlaTnDYzU+1BrT2vRpL+NCntUsldHFf08nadV/XKl9t119xdjIF2oPF7NZOtu6PsDu9KpxNpnlPzbCvrqfGmCPeX/thmBT/i82qQqJKcl+WE0mI49qxNIaPIWphIZx/9vVxA30FrO8uy+ijIBmT8fZJtDlCcVIakagNJGUMaowTs49mTRWPq4VGZl7IhNDclpDwm7jULsFmX9r6hMUCgzu1ZEMnab2KGF5Y4tE5++9Jmr79suUY9l/+I7HEwDTFMc7HSCb1vvEtAdVbQszvJDw1XqZant6fDa/p+r69suUY18LR6pTnxqOv11cQSObhYLf7109b90wFBZ2UcB6+11uitexrRHXL2CnKQf2i5RtMPxUN29TGqZrAexlT3VzU/s0umXjYhX7MFdocO+Aujq9NaJceee2uoFuYqs7qpgWxJ7sbVE8rt3+2+r4UkayxqB4++xdsVQ9ngGOtaeTwKPK4bFSk42+J5ve4o9qJvRwnugNPdyo6sQAEygnjjRT1W2f1L2zt0ktZliO5/7a21rPqRLd0F6ZQkx9fixZ98O6Ptxy9+3Zfrly3Rx/KNt1Ux26NvKWInQXboILF5fl76YjMueqzQkI24uZk9XuGRGRpGFYhIl84VRFPBGDguMzsiS91/MjT33Sl8c86+mSYUIsJ9n9cK9hwdVZ6nDAlSu23hMbnns6k8NyqpBwfI3vf/z8mmH5g8f+cdWiBt/8+U6P/OIq8YHbEkUed7l/rZp6b47SG1UK7eYojY05rjopI40xlQOk11f/h1F0Peb5WDa7am/Xlt+XqxauQ191POvmbL1Q9UNsnwNUndzjMKZqEv/Np1DOhzyOivbGG884UTPc17at2/KX/QGecO+FvDGrerM5Ovb4xuZ0GJfxreaofKq222JU4Wwxx3tsOdmL84nV5DHv0cXXq/vJtdcx/2b7wvSLNlZL3nNsdOEpTIwpxryfa9r4Y/Kt5qh8XlXHv3VTzu2PX6rxezGWJ2NZOsvUWh92XdUOzoXt3+/VeV18pfZetlCxTsVU01eYRuQJeVazVJryUK7gGM4TuRqlaoRHqnXN57hAbzHLu0nJ+dhUz88T79fm7hwvhrO0mng37z2t6V5+TMOcYJt6S+YM2+V3FW1OPKGp9mTcP5yaBO5HZySDCA6rdrPat1s3jijbFmP0odG9Kj12nNoCDMsey26vT826/HW1fz7hNN9YQdyF2+uFy8tytN9NmVEWd+F9yxLfKxMtxfSmmVH9sLfsLW8qgHfNvCcQVIC//fJ2W8Ia3P9yp1D3vSXG97loYwPjSaXeaKbGSG5NIJOQXTOh9IS/5xWo9DYzFQ6rzQb3P4HI1WyuTjzzOxSaTv2eUIocBxaoTBwFNlSg1eOHarWt8VNzP92tgnjukmtIX7rIA3KftUUDtFDtajdXKV4Zg7uarI3jKpU5YHbX1bTX8iPOtw71PPuJbZVTyvX+O/uMJiXr/ePZcK5WNKx9ncm4ntA4foUnMhKR3uoGFVp9zNnB76r1Jzga9X++WzUiLpOrklfSGGM331MpN+fjkHG9ovL9RedjkccrWWIZ2t9O5jDFbfmh3JbraGMLi9Lu+mtb79olJVqv9t+/1F3FPi+LVYlPxpzDZC/cBBfepSzG9MZSPPWXLNHflE+r7vFGzjQfivf2E6ebpyjvunEeHk8PVa+2SxTN2PKW6Ouq4Z0irinbevtatm+31apNfM3na1aXa5aUINpEU9nJZhpq0UbUdHbvzCn4uMu7/ny3RpS4TG5EvZLOGJNQ1ZRxybRiX8miIwaq2ttPjhimlVPGK1T9ljHLdAlGxy1UOmnsMq0ZrRxUb7JyQC1aOf7o/hoRdD/drVJ47pIrRF+6sd78fRk5fSBUtLZNOXEQwaRie+ja4PdmtjqtaG2b3nauosnbMXkz+8339TbhyV7t1739bOV46AeC00E/rrOumnVkNB2EzNlstk43fYp82pMoXQ2XaKUJLVKpm33ZvF9tKkhwaZUzxs3ZeK4mPk0slBo/SGxKoRtJIvISSvRGszVi60WBxtSC0ZRGU95Sc6/2S2tu7JQIojdxesOUSuQjCKHIxBcQJjXaI850JCpns7k6VeQAj1Bm6uyOKZVt+QrP2A1VzlZzVXbVvlodT031z6TWbmA+V7fe269GTArW+3VvN1/p5xqfxkyVXurxs5gnlQ6rNT5plihd7OYqja0v+0opC8zjSma1YLV/TggN33K+WpsYiL7lXLXo4NkXmhw4T2h07zoh+C5mS3RSIuJqN1vp2NSfpl/QxWyZzh/VJrK+MxT73NvOVYwcGhhKTU4UJzTM94umB0UXs7k6r2l94evSvvBz+fhaldPV6Go3W8n++jHyoSiiZv976ltRU4r/THuG/5zxDMOJ9d/t5vH4J2+C3+80xR76TJxnh4Wds68JSCdta4opJ26lB7LTW+qTNMf32QDdtG02adqRpCCkOpEclKgHk4Sg3GiyUDSOgqpx+aQ00Lz8dqcqEfpLrA7XAs6pCkQyqRpMKjblavPVpGqjhpIoWtv2OJ7jghSTVjDoE51YwpjUiVduojRdsSe1IkehE6GJc9ATVI7fm6cy0n4MFI/2OSY0ICnqP5rj2G5SL80Vd1L/zeGxm/R7pHanEvx+KPc3ydfdBTO1I03b9/V+H4V7wOrezR3xfGvD5xV/URNIi3FbYwhLcVsjNXgOqc3VtHZCw0XVb2jCpvWnGjMqntqs4XcfhnkVYUZ3JUa386LhmDw4+uVw2Ma/JhKQm8BynlpsDfaWFdhxBbgnLViuHH3f477bn+p15PtxgUT7dLGbrXTabtvYCddEzDedq/dbta921T8T7m3nWc5V6wZt+82qmRZrr4ZzteKfCg6lpr8SPK6Et0MGq5QLYm8kAzaQmE6AHddJirmF0RZB04HCOJEe9x/7yPZg4ekWhZB4f/lxW0Y28gZt5pfyYjdPaV2aDVW/76On3QcdgjXueoWb30/aAMKXmhozjCrY9nGqH+ht5imcW6kJEc9snk6zqiaf1dlmnsKxfn7elsn9gTOf1ycEuqd94jMMDNNrrDd4+tsv3UDr72h59fLLXYZPobek8dO1aJHGZr3a/1v9HZpUUbXV/rkenUylaf1UN59R14nkni62MxW7sXm1Wx3LzbumfobfBSaylwsO1wtmalftr/UK4j+iWbXbi+FMLdxlEJ3xPmNSw/ieUHAm6f4HSVF9cPxb9xpODUhjJXrmkj5Gnq+XzNTvqtOxM/3ukmuVUP/MBY/+BTO1y9fV9t8/RD4hRkO0s/2zbc62cxW/lOt//zCp1Vn9ueCZPic1LTPaFaKS2KjMa1FI/qrNAITwm9brwHSm3rbaf3pnvmBQfp6sDsb2cLWdq9g1Rj9//O3XSbXObtir3ar0t/dJQotalt3qeX/55GRq2xJctLx1qfemN/j+pevWJgOn3ptbXp9tZyv+dfVaPSO8MNDbXy2XqnVP64dyXcF94zHdznZzvWZ2CSx0Tn3Etjdc+oyb0rypKbGL1UwVQ+gSxxLGdM5oggzZ6+3janL8eTWbqXNqy+btM5qG0nFFZ7h6HpuHelr/+U3XSG/KL2/+8j9vXsvGBtVf3rBv+bfmDJ2nqtxuuqv/4QrR+at3/Qx3083Y7H/+Z2/2d7sFyxg76399ePPNPx6+UeJbofP//M9v/nG+2P5g/3D2cf2LvTDr/pWhC7PBhVlwIev+xdCFbHAhCy7k3b84upAPLuTBhaL7l0AXisGFIrhQdv+S6EI5uFAGF6ruXwpdqAYXquBC3f1Lowv14EIdXJh3/8rRhfngwjy4sIugfxTowmJwYREGgImHDMZONgyejESPDZ/sG1l8y3V4LYifMIAyExYZDKFsGENZGESZCY0MhlE2jKMsDKTMhEcGQykbxlIWBlNmQiST6JaH4ZSF8ZSZKMlgRGXDkMrCmMpMpGQwqrJhWGVhXGUmWjIYWdkwtLIwtjITMVmBbnkYXVkYXswEDHv4RohvsyxsJ4bRxcLoYiZgGGyd2DC8GGmfbAOFWyjQRIXhxUzAMBhebBheLAwvZgKGwfBiw/BiYXgxEzEMtlZsGF8sjC9mIobB+GLD+GJhfDETMQzGFxvGFwvji5mIYTC+2DC+WBhfzIQMg60XGwYYCwOMm5jhsP3iwwjjYYRxEzM8A9HJhwHGwwDjJmQ4DDA+DDBOOkHbC+JuEPSDYYBxEzIcBhgfBhgPA4zLWIXkw/jiYXxxEzG8a/vUtw8PMrx4GF88jC9uIobD4OTD+OJhfHETMRwGJx/GFw/ji5uI4TA4+TC+eBhfwsYXDE4xjC8RxpcwISNgcIphgIkwwIQJGQGbPzEMMBEGmDAhI2B0imGACTLSErFqIcBYK4wvYUJGwMgWwwATYYAJEzICD/KGASbCABM6FtliGF8ijC9hIkbAZlcM40uE8SVMxAgY2WIYXyKML2kiRsDIlsP4kmF8SRtfOeiZ5TC8ZBhe0oYXDGw5DC8Zhpc0ASNhYMtheMkwvGQ0vOQwvCQZy9vBPKwUEgznw/CSJmAkrBRyGF4yDC9pIkbCwJbD+JJhfEkTMRIGthzGlwzjS5qIkXgGM4wvGcaXMhEj8SxmGF8qjC9lQkbC4FTDAFNhgCkTMhI2u2oYYCoMMGUDDEanGgaYCgNMmZhRMDrVMMJUGGHKxIyCEaaGEabIjFHF2iAF5oxhgCkd7V3VMMBUGGDKhIyCoa2GAabCAFMmZBQMbTUMMBUGmH6I1WY9jC8dxpc2EaNgtdDD+NJhfGkTMUp+I/S3GWfhxcP40mF8aRMxClYLPYwvHcaXtvGFJ/jD+NJhfGkbXzl6zXoYXzqML22XJGC10MMA02RVwi5LdMHZKZPnBdYlwvjSJmI0rBV6GF86jC9tIkbD4NTD+NJhfOUmZDQMznwYYHkYYLkJGQ0DLB8GWB4GWG5CRsN2Nx8GWB4GWG5CRsMAy4cBlocBlotYM5IP4ysP4ys3EaNhcObD+MrD+MpNxGi8AjWMrzyMr9zGFwzOfBhgOVn5sktfsM3OweJXGGC5CZkcRmc+DLA8DLDChEwOo7MYBlgRBlhhQiaH0VkMA6wIA6wwIZPD6CyGAVaEAVaYkMlhdBbDACvCACtMzOQwOothhBVhhBUmZnIYYcUwwoowwgoTMzmMsGIYYUUYYYWJmRyvcw4jrAgjrDAxU8AIK4YRVpD1VbvACiOsAEusdI3VBE2B1zof0CorWWZ9MHFT4OXOB7DS+kCWWh9YrI92P9HLyWLrgwmeAi+YPoDl1gey3vpg4qeAoep+o9eTJdcHE0IFXjd9AKuuD2TZ9cFEUYGXTh/AwusDWXl9MIFU4NXTB7D2+kAWXx9s5MEF1Aew+vpAll8f7PrrQ2SNHizBPpDw69f4MedBq/yDZX67zv+AAxgu9ZMAdIv9DziC0XI/Xe93C/5w2R0t+NMVf7fk/4BDGC3601V/t+z/gGMYrfzTpX+39v+Agxit/tPlf7f+/4CjGBEAigAcA3jAYYwoAMUAjgM8wOY3QyiAsIDMru9nEdgEeEBGgEDGHG/CgQyYQEagQGbX+bMYdULYicShXevPIuQJsIGMwIHMrvd34YUiGeCBjPCBzC75d9GFCwACkTCCzC77ZxEKBTBBRjhBZpf+swiJAqggI6wgs8v/WYRGAVyQEV6QWQTQRRd2AAKRMIPMYoAuujA/BIFIuEFmWUCG2VQG2EFG4EHGHf3EgQj4QUYAQmaZQIYZVQYYQkYgQma5QIY5VQY4QkZAQmbhQIZZVQZgQkZoQmYBQYZ5VQaAQkaIQmYhQYaZVQagQkaoQmZBQYa5VQbAQkbIQmZhQYbZVQbgQkboQmaBQYb5VQYAQ0YIQ2ahQRde2AGIREIZMgsOMgyyMgAaMkIaMuFYPI5EABsyQhsySxAyDLQyQBwyghwySxG68MIOQCQS7JBZkpBhOJUB8pAR9JBZnJBhQJUB/JAR/pBZpJBhSJUBBJERBpFZrJBhUJUBDJERDpFZtJBhWJUBFJERFpFZvpBhYJUBHpERIJFZxpBhaJUBJpERKJFZzpBh+JQBLpERMJFJlxmCIxHAiYzQicwChwyDpAwAiowQisxChwzDpAxAioxQisyChwwDpQyAioyQiszChy68sAMQiYRWZBZAdOEFU2RAIBJgkVkGkWG4lAFmkRFokVkOgReGM4AtMsItMosiMgyZMoAuMsIuMuUmKziQAb7ICL/ILJLIMGzKAMLICMPIlMtSwoEMMEZGOEZm2USGoVMGWEZGYEZm+USGwVMGeEZGgEZmGUWG4VMGmEZGoEbmqAZcaM8A1sgI18i0i0NcEQDbyAjcyCyv6MIbVQSANzLCNzKLLDLMsTKAODLCODKLLTLMsjKAOTLCOTKLLjKMlTKAOjLCOjIHO3BVBLQjI7gj0y5jDlcEQDwygjwyizEyjJgygD0ywj0yizK66oEdgDAk7COzOCPDqCkD+CMj/COzSKOrHt8I+e1DVoQOAALJCAPJLNboqsc3gn/LtCIOQCASDpLlLhDx2AKgkIywkMzija5+YAcgEAkPySzjyDB/ygATyQgUyfJo2lMGqEhGsEhmSUeGEVYGyEhG0EiWu+xNHMiAjmQEj2SWeGQYZWWAkGQEkWSWemQYZ2WAkmQEk2SWfGQYaWWAlGQElWRFNNsuA6wkI7Aks/wjw2QrA7wkI8AkK1wU4gYdMJOMQJOscFGI6wHgJhkBJ5llIV39hH0SYCcZgSdZEc0vyAA9yQg+ySwRyTAoywBByQhCyQqXR4zrAaAoGcEoWTHSKQOQkhGSwiwZyTBwYwClMIJSmEUjGYZuDLAURlgKi7MUBlgKIyyFWTaSYW7HAExhBKYwC0cyzO4YoCmM0BT24IIQZ/oCnMIITmEWj2SY4THAUxjhKczyETwqYICnMMJT2IOLQpwxDIgKI0SFOaKCWSADRIURosIcUSnQzgcGgAojQIU5oIKJIANAhRGgwhxQwUiQAaDCCFBhDqhgqMcAUmEEqTCHVDDVYwCpMIJUmEMqGOsxgFQYQSrMIRXM9RhAKowgFeaQCgZ7DCAVRpAKc0ilwIEIkAojSIVZQsIw2mMAqTC6vaLfX4E3SaAtFnSPhdtkgdEeQ9ssBvss7EYLjPYY3GpBItFttnhARISh3RZ0u4Xbb4HRHEM7LuiWCxafpDC06YLuunDbLjDaY2jjBd154bZeYLTH0OYLuvvCAhKY2cXQ9gu6/8JtwMBkkKEtGISnMO6iENcDwFMY4SmMu60+DygGAE5hBKcwS0cYBoMM4BRGcAqzdIRhMMgATmEEpzBLRxgGgwzgFEZwCnMbM/C2NAZwCiM4hVk6wjAZZACnMIJTmKUjDJNBBnAKIziFWTrCMBlkAKcwglOYpSMMk0EGcAojOIVZOsIwGWQApzCCU5ilIwyTQQZwCiM4hQm37wxHIsApjOAUZukIi+xcAziFEZzCLB1hkd1rAKcwglOYpSMstoMNRCLBKUxEZykMwBRGYApzGzkim+AATGEEpjDLRlhkIxyAKYzAFGbZCItshgMwhRGYwiwbYZENcQCmMAJTmHRxiAMZwBRGYAqzbIRhsMgATGEEpjDp9kDiQAYwhRGYwiwbYRgsMgBTGIEpzLIRPNMCKIURlMIsGWGYSzKAUhhBKcySEYa5JAMohRGUwiwZYZhLMoBSGEEpzKIRhrkkAyyFEZbCLBphmEsywFIYYSnMshGGuSQDMIURmMKUi0McyACmMAJTmGUjDHNJBmAKIzCFKbcfFwcygCmMwBRm2QjDXJIBmMIITGFuVwjmkgzAFEZgCrNshGEuyQBMYQSmMMtGGOaSDMAURmAKs3CEYS7JAE1hhKYwC0cY5pIM0BRGaAqzdIRhLskATmEEpzBLRxje8cYATmEEpzBLRxgGkwzgFEZwCrN0hGGwyABOYQSnMO12h+NIBDyFEZ7CLB5hGCwywFMY4SnM4hGGwSIDPIURnsIsHmEYLDLAUxjhKcziEYbBIgM8hRGewiweYRgsMsBTGOEpzOIRhsEgAzyFEZ7CLB5heHcbAzyFEZ7CLB5hmAwywFMY4SnMbTDBZJABnsIIT2GOp2AyyABRYYSosNydVYAjERAVRogKs4CEYbLHAFFhhKgwC0gYJnsMEBVGiAqzgIRhsscAUWGEqDALSBjeSMYAUWGEqDCLSLq2GjsAkUiYCrOIhGGyxwBTYYSpMItIGCZ7DDAVRpgKs4iEYbLHAFNhhKkwi0gYRnMMMBVGmApzTEVztPYAoAojUIUV8X2bDDAVRpgKs4iEYbLHAFNhhKkwy0gYJnsMQBVGoAq3jIRhsscBVOEEqnAHVWBSMwdMhROmwi0kYRjtcUBVOKEq/MGFIT7jAVAVTqgKf3BhCCsCB1SFE6rCLSRheAMbB1SFE6rCLSTpugr4DMHpGgSqcAtJGEZzHFAVTqgKf3BnuOBDSQBV4YSqcAtJup4C3gE4aINAFW4hCcNojAOqwglV4Vk88YsDqMIJVOGWkTCM1jiAKpxAFW4ZCcNojQOowglU4ZaRMIzWOIAqnEAVnrkwxHEMoAonUIVbRsIwGuMAqnACVXgWh3scMBVOmAq3iIThrXYcMBVOmAp3TAWzNQ6YCidMhTumgtkaB0yFE6bCHVPBbI0DpsIJU+GOqWC2xgFT4YSpcMtIIi8BMBVOmAp3TAWzOQ6YCidMhbtzrDCb4wCqcAJVuIMqmM1xAFU4gSrcQRXM5jiAKpxAFW4pCcdsjgOswglW4ZaScMzmOMAqnB5t1Z9thSMZnW5Fj7dy51thNsfREVf0jCt3yBXeN8fRMVeDc67sQVcYznF41BWJRHfYFYZrHB13Rc+7spiEY7jG0ZlX9NArd+oVpmMcnXtFD75yJ19hOsbR2Vf08Ct3+hXeN8fR+Vf0ACx3AhbGYxydgUW4CnenYGUMde0Aq3CCVbiI8z0OqAonVIULl3SDAxlQFU6oCreQhGO6xgFV4YSq8P5MLBzIgKpwQlW4cKvZOJABVeGEqnCLSTimaxxwFU64CreYhGO6xgFX4YSrcOHiECU0c4BVOMEq3FKSrreE14MoJFSFW0jCMVvjgKpwQlW4hSQcszUOqAonVIVLd+gfjkNAVTihKrzfogIfIYAqnEAV7s7OwmyOA6jCCVThDqpguMYBVuEEq3BLSTiGaxxgFU6wCreUhGO4xgFW4QSrcEtJOIZrHGAVTrAKly4OcYMMsAonWIWr6KmmHEAVTqAKt4yERw6tBFCFE6jCVTQHkQOkwglS4ZaQROohICqcEBVuAUk3VoDXgxgkQIVbPsIjZ2cCoMIJUOGWj/DI+ZkAqHACVLjlI/DgPA5wCic4hVs60o004PUgAAlN4RaOcAwGOaApnNAU7g7dip2mCUKQ0BSuXQjiSghoCic0hVs4wiOnagKawglN4dodgQpbQgBTOIEpXLtTUHElAjCFE5jCLRvhmAtyAFM4gSncshGOuSAHMIUTmMItG+GYC3IAUziBKdyyEY65IAcwhROYwi0b4ZgLcgBTOIEp3LIRjrkgBzCFE5jCLRvpRhooDABL4YSlcItGOMaCHLAUTlgKt2ikG2p8wx++7foq4gAEImEpPB9pDQFK4QSlcEtGOMaKHKAUTlAKd5tTsD6IQgJSuOUikcYMcBROOAq3WIRjqskBR+GEo3CLRTimmhxwFE44CrdYpBsqfSP5t6Igyx2Ao3DCUbjbmYKpJgcchROOwi0W4ZhqcsBROOEo3GKRLvzwLYAoJByFWyzSDZW+EcW3eUYOZwYchROOwgsZb48BRuEEo/DCHQ4dOWYZxCHhKLznKLgAIA4JR+EWi3AMRTngKJxwFG6xCMdQlAOOwglHERaLcAxFBeAognAUYbkIx1BUAJAiCEgRbnMKhqICgBRBQIqwXKQbb6E4FACkCAJShOUiHENRAUCKICBFWC7SjbhAGAjAUQThKMJyEY6ZqAAgRRCQIh7cQeWRI7/BUdIEpIgHd1g5PvYbgBRBQIqwYIRjJioASRGEpIjsId6nCUBSBCEpwpIRjqGqAChFEJQiLBnheL+jAChFEJQiLBnpxmwIqwqAUgRBKcKSEY6pqAAoRRCUIiwZ4ZiKCoBSBEEpwpIRjqmmAChFEJQiLBrhmGoKwFIEYSkic5GIQxmwFEFYisjc0fmRE+xBJBKWIiwa6QZtqFsSgKUIwlKERSMcY00BWIogLEVYNMIx1hSApQjCUoRlIxzvGBQApggCU4RlI92oDbVogKUIwlKERSPdsA1eD+KQoBTBounYAoAUQUCKsFyEY6gpAEgRBKQIB1Iw1BQApAgCUoQDKRhqCgBSBAEpwoEUDDUFACmCgBQR/1CIABhFEIwiHEbBTFMAjCIIRhEOo2CmKQBGEQSjCIdRMNMUAKMIglGEwyiYaQqAUQTBKMJhFMw0BcAogmAU4TAKZpICYBRBMIpwGCXSKwKMIghGEQ6jYKgpAEYR9Fsi/cdEcji6Qp8Tod8TsVyEm6NEkQMQifSbIu6jIg9o6U+gr4rQz4q474pgpinQl0UGnxZx8xQ40RHw8yIkEN0HRh4YdgACkX5jxH1kBENRgT4zQr8zYrGIMBsWUQlAINKPjbivjWAoKtD3RugHRxxIwZM9gb45QkiKcF8deVBwdAVIiiAkRbgvj2CqKgBJEYSkCPf5EUxVBSApgpAUIV0k4k4BoBRBUIqwZERgqioAShEEpQhLRgSmqgKgFEFQirBkROBNhwKgFEFQirBkRGAsKgBKEQSlCEtGBMaiAqAUQVCKsGREYCwqAEoRBKUINTZVATBFEJgiLBvphs7fiOxbTWsjgCmCwBSh3HeW4IQT0BRBaIqwdERgrCoAThEEpwjlAhFHMuApgvAUYfGIwJsWBeApgvAU4U77wicECcBTBOEpwvEUTGYFICqCEBWhxvpmgFQEQSpCuSMd0CqoAERFEKIiLCARGA0LQFQEISrCAhKB0bAAREUQoiI0GwlkQFQEISpC83ggA6IiCFERjqhE5mqAqAhCVIR2cYhbE0BUBCEqwgISgeG0AERFEKIitItDOFUCQEUQoCIsHxGYTQsAVAQBKsLtToGHGQjAUwThKaI/7AvXRMBTBOEpIndhiFsjAFQEASrC8hGB4bgAQEUQoCLGgIoAQEUQoCIsIBEYjwtAVAQhKsIRlUggA6IiCFERFpEIM98bHKggAFIRBKkIh1TwjB8gFUGQinBbU+CMHQAVQYCKsHxEYL4uAFARBKiIIvpNJwFwiiA4RVg6IjCeFwCnCIJThMMpkRACOEUQnCIsHRF4664AOEUQnCIKMdIYA5wiCE4RFo8IvC1EAJ4iCE8RhYvByGcFQRASniIsHxEY8QsAVAQBKsLyEYERvwBARRCgIgoXh7gpAUBFEKAiLR8RmPFLAFQkASrS8hGBGb8EQEUSoCItHxGY8UsAVCQBKtLyEYEZvwRARRKgIi0fEZjxSwBUJAEq8kFGGzMJgIokQEVaPiJwjoAEQEUSoCItHxE4R0ACoCIJUJEOqGAoJQFQkQSoSMtHROwrm8NAlASoyMwFIqwKEgAVSYCKzFwg4s9tAqAiCVCRlo+IyCc3AVCRBKhIy0fgGUES4BRJcIq0dEREvrwJcIokOEU6nILbdAlwiiQ4RVo6IiRDLaoEOEUSnCItHRGRT3gCnCIJTpFuawrcoiUBTZGEpkgLR0TkM6CApkhCU6SFIyLyKVBAUyShKdLRlMhLADRFEpoi2cgkRQKaIglNkRaOCLx9WwKaIglNkcwFIq7LAKdIglOkwyl4DVUCniIJT5HMBWKOqhIAKpIAFek+oIIP9JUAqEgCVKT7gAqeJEgAVCQBKpK5QIx8/BcEIgEqko+s2kgAVCQBKtISEoGTNSRAKpIgFWkJicDJGhIgFUmQirSEROBkDQmQiiRIRVpCInCyhgRIRRKkIvnIabASIBVJkIq0hETgbA8JkIokSEVaQiLwFngJkIokSEVaQiJwtocESEUSpCItIcETdgmIiiRERVpAEhncAKAiCVCR7gvteAu+BEBFEqAi3edTYNaSBEBFEqAiHVDB6SoSABVJgIp0QCVSFQFQkQSoSAdUFL4DEIWEp0jHUzRCShLgFElwinQ4RcNeFdAUSWiKdDRFo71JEsAUSWCKdDAl0h8AmCLpF9z7T7jjhgB9xJ1+xV2O9croS+70U+4OpuAjBCT6mjv9nLuDKThZRqIvutNPujuYgpNlJPqs++C77jYKcbKMhJ92J2HoYApOlpHo8+70++4OpuBkGYk+8U6/8e5gCk6Wkegz7/Q77w6m4OO5JfrUO4Ep0rIRgZNlJIApksAU6WAKTpaRAKZIAlOk25mCyaQENEUSmiIdTcHZNhLQFEloinQ0BZ8iIAFNkYSmSEdT8CkAEtAUSWiKdLtTItUZ0BRJaIp0NAW3yACmSAJTpMrjLTJgKZKwFKlcHHYvMf+W54I4AHFIYIp0MAU36YClSMJSpGMpuEkHKEUSlCLd5pRIkw5QiiQoRTqUglOWJGApkrAUqcd6ZcBSJGEp0rGUyEQLsBRJWIp0LCXyEgFLkYSlSMdScNaVBDBFEpgiHUzBWVcSwBRJYIq0cETgtCkJaIokNEVaOCJw2pQENEUSmiIdTcFpUxLQFEloinQ0Bc8VAUyRBKZIy0YETruSAKZIAlOkgyk47UoCmCIJTJGWjQicdiUBTJEEpkgHU3DWlAQ0RRKaIi0dEfgoCAlwiiQ4ReYuEHEkA6AiCVCRlo9IfBSEBEBFEqAiLSGROG1KAqQiCVKRlpBIfBSEBEhFEqQi3ddTIosOAKlIglSk+3pKZNEBIBVJkIq0hETivCsJkIokSEUWYyuIAKlIglSk26KCuaAESEUSpCKLkcwvCZCKJEhFWkIi8XkaEiAVSZCKLFwk4uoMkIokSEU9uEiE1VkBpKIIUlEPLhJhdVYAqSiCVJRDKngdVwGkoghSUZaQSJw6pgBSUQSpqAcXibA9UACpKIJUlEUkEqeOKcBUFGEqyiISiVPHFGAqijAVZRGJxKljCjAVRZiKsohE4tQxBZiKIkxFWUQiceqYAkxFEaaiLCKROHVMAaaiCFNR2ci0WQGmoghTURaRSHwkhwJMRRGmojIeH6QpQFUUoSrKfUQFLwEqQFUUoSrKQhI8vlAAqigCVZT7hgruFhSAKopAFeW+oYK7BQWgiiJQRWUuEHF7AqiKIlRFuT0qsTAAgUioinJ7VPCcVQGqoghVUczNmuFQWwGqoghVUW6PCgacClAVRaiKclQFZxsoQFUUoSrKQhKJkxgVoCqKUBXFXJOI21RAVRShKspSEomTGBXAKopgFWUpicQ5iApgFUWwiop/RUUBqKIIVFGWkUicQagAVFEEqqgxqKIAVFEEqigHVeBiuAJMRRGmonh8sqIAUlEEqShLSCROgVQAqSiCVJT7Jn2kNQJIRRGkohxSibRGAKkoglQUd1GIezWAVBRBKsrtUom9RBCFBKkoS0gkzoFUAKkoglQUd3EIc/sVYCqKMBVlGYnESZAKQBVFoIpyu1TwfnwFoIoiUEVZSCJxEqMCVEURqqKEi0TcGgGqoghVUULEqxKAKopAFWUhicQ5jApQFUWoirKUROLPbyiAVRTBKspiEsnxMBtwFUW4irKcRHKOHYBAJGBFiSLenACuoghXURaTSJzEpwBXUYSrKItJJD5mRwGuoghXUXIkD1EBrqIIV1GOq+AwAlhFEayiHFbBjxBQFUWoinLfo480qICqKEJVlDvtCx78pwBUUQSqKOmiEA+xAVRRBKooOZLroABUUQSqKMtIJE6DVACqKAJV1NgOFQWgiiJQRY3tUFEAqigCVZRlJJLDr6YqAFUUgSrKMhKJEzEVgCqKQBVlGYnEiZgKQBVFoIpSI2s3CkAVRaCKsoxE4kxOBaCKIlBFWUgicSanAlRFEaqiLCWRAreHAKsoglWUwyq4MQBURRGqoiwlkTgTVAGsoghWUXpswgy4iiJcRVlMInEqqAJcRRGuoiwmiT1DwFUU4SpKj/TLAKsoglWUpSQS56IqgFUUwSpKj8A9BbCKIlhFaReHaJeOAlRFEaqitAtDdHadAlBFEaiiLCOROBNVAaiiCFRR+Vh7CKCKIlBFWUYiJcKTCjAVRZiKsoxE4lRUBaCKIlBFOaiCl3EVgCqKQBVlGYmUsFcETEURpqJyGY8BgFQUQSoqV/EYAERFEaKiLCCROBNWAaKiCFFR+ch2PQWIiiJERTmiglNhFSAqihAV5YgKToVVgKgoQlSUIyo4EVUBoqIIUVFukwrezK8AUVGEqCgLSCTOZFWAqChCVJQ78wufkaMAUVGEqCgLSCQ+s0sBoqIIUVFjREUBoqIIUVE9UYG7+RUgKooQFeWICk5lVYCoKEJUlCMqOBNVAaKiCFHRjqjgTFQNiIomREU7ooIzUTUgKpoQFW0BicSZqBoQFU2IinZEBSeSakBUNCEq2hEVnEiqAVHRhKhoR1RwIqkGREUToqIdUcGJnBoQFU2IinZEBSdiakBUNCEq2hEVfG6YBkRFE6KiHVHB54ZpQFQ0ISraERV8bpgGREUToqItIJH42C8NiIomREU7ooJTITUgKpoQFW0BicSZjBoQFU2IiraAROJMRg2IiiZERY/tU9EAqWiCVLQlJHh4owFR0YSo6ExHBxcaABVNgIp2QAWnYmoAVDQBKnoMqGgAVDQBKpq5OMR1EQAVTYCKZi4O0fhGA56iCU/RY7tUNOApmvAUzVwY4roMeIomPEU7noJzQTXgKZrwFM1G9jBrwFM04Smaua4ZZdZrgFM0wSmaufQvCLU0wCma4BTN3PohXIDUAKhoAlS0Ayo4HVYDoKIJUNGWj0icDqsBUNEEqGjuFhDhdFUDoqIJUdEjREUDoqIJUdF8JOlGA6KiCVHR3MUhbpABUdGEqGg+1hwCoqIJUdHus/Twq2AaABVNgIrmDutBnKEBUNEEqGi3RyXSGACgoglQ0Q6oRO4AhCHhKdrxFJyRrAFP0YSnaLdJBZ/WpAFP0YSnaMdTcEqzBjxFE56ixciZDhrwFE14ihYj++k1ACqaABVt+UiBUqI1wCma4BTtcAo+xFADnKIJTtEOp+CMYA1wiiY4RYuRKbMGOEUTnKLFCNfTgKdowlO026cSeQeAp2jCU7TjKTgjWAOeoglP0Y6nYDCoAU/RhKdoy0ckTinWAKhoAlS0FPG6DICKJkBFy3i+jQY8RROeoi0fkTilWQOgoglQ0Q6o4JRmDYCKJkBFWz4icUqzBkBFE6CiHVDBKckaABVNgIq2fETilGQNgIomQEVbPhKhWhoAFU2AilZspFsFQEUToKIdUMFJ0RoAFU2AinZABSdFawBUNAEqegyoaABUNAEqWqmRTgUAFU2Aina7VHAepwZARROgoh1QwXndGgAVTYCKVmMTFUBUNCEq2hEVnBiuAVHRhKhoPZLpoAFR0YSoaLdTBR+HqQFR0YSoaAtIFE5N14CoaEJUtCUkCqema4BUNEEq2hIShVPTNUAqmiAVbQmJwonhGiAVTZCKtohE4axqDZiKJkxFu++owDPnNWAqmjAV7ZhKZKoDmIomTEXnLtUBTzQAU9GEqWjLSBTOC9cAqmgCVXQ+sj9AA6iiCVTRuQtE3CQCqKIJVNG5C0TcJAKqoglV0bkLRNyeAKyiCVbR+Qjb04CraMJVdO4CEbcngKtowlW0xSQKJ5ZrwFU04SraYhKFE8s14CqacBVtMYnCieUacBVNuIq2mEThxHINuIomXEVbTKJwYrkGXEUTrqL7nSo4lAFX0YSr6EKMDA8AV9GEq2iLSRRObdeAq2jCVXQxFomAq2jCVbTFJAqntmvAVTThKrpwkYhrI+AqmnAVXcSzHTTAKppglfzBBSKszTnAKjnBKvmDC0RYGXOAVXKCVfKHkeyvHGCVnGCV3FISZc7xG67h5QCr5ASr5A6rwHXQHFCVnFCV3EISxdA+3BxAlZxAldwyEsXQUnQOmEpOmEr+MEL3csBUcsJU8odoSnYOiEpOiEpuAYnCCck5ICo5ISr52IdUckBUckJUcvdJeobmmzkAKjkBKrnlI7EQAkAlJ0Alz1wMoqMoc8BTcsJTcotHFDygJQc4JSc4Jbd0BL9BAFNyAlPyzEUgbIZyQFNyQlNy9zl6nEqcA5ySE5ySZyPrNjnAKTnBKXnmghC3QwCn5ASn5JaOKJxLnAOckhOckls8onAucQ54Sk54Sm7xiMIHiuaAp+SEp+Tue/T4RNAc8JSc8JTc4hGFc4FzwFNywlNyi0cUzgXOAU/JCU/JLR9ROJM1B0AlJ0Alt3wE1wSAU3KCU3JLRxTOY80BTskJTsnZyGw5BzglJzglt3Qk0pYBmpITmpJzF4a4KgKakhOaknMWb8sATckJTck5j7dlAKbkBKbklo3gNwhQSk5QSs5dCOKGAKCUnKCUnI+MCnPAUnLCUnKLRhRO480BS8kJS8ktGlE4CzcHLCUnLCW3bEThLNwcwJScwJTcshGFz1PNAUzJCUzJLRtROIs2BzAlJzAlt2xE4STYHMCUnMCUXIwNCwFMyQlMyS0bUTiJNQcwJScwJbd0ROHzUHOAU3KCU3JLRxQ+DzUHOCUnOCUXOj4yBTQlJzQlFy4QcV0CNCUnNCXvT/2C2Xs5oCk5oSm5+xg93rOZA5qSE5qSWzii8ImuOaApOaEpuYUjCufB5oCm5ISm5BaOKPzh1RzQlJzQlNzSEYXzSHOAU3KCU3KLRxROA80BT8kJT8ktHlE4DTQHPCUnPCW3eEThNNAc8JSc8JTc4pHIHAnglJzglNzSEYWzQHOAU3KCU3JLRxRO4swBTskJTsktHcHdGoApOYEpuXJhiKsigCk5gSm5ZSMKZ2DmAKbkBKbklo0onIGZA5iSE5iSWzaicAZmDmBKTmBK3u9Ogeu3OYApOYEpuWUjCqdw5gCm5ASm5JaNKJzCmQOYkhOYkjuYkiHCngOWkhOWkls0onAKaA5YSk5YSm7RiMIpoDlgKTlhKblFIwqngOaApeSEpeR6JMshBywlJywl1yNZDjlgKTlhKbk79QsnXeWApeSEpeQ6fjZxDlBKTlBKrkfOJs4BSskJSsn1yH69HLCUnLCU3KIRhfNwc8BScsJS8rH9KTlgKTlhKXk+sl8vBywlJywlz10g4hYRsJScsJQ8HxshApaSE5aSu1O/InEEWEpOWErudqjgLYc5YCk5YSm5RSMKJzPngKXkhKXkjqXgZOYcsJScsJTcsRSczJwDlpITlpI7loKTmXPAUnLCUnLHUnAycw5YSk5YSl6MbNjLAUvJCUvJi5FE2BywlJywlLwYi0TAUnLCUvJiLBIBS8kJS8mLsUgELCUnLCUvXCTijgmwlJywlLwYOdIhBywlJywlt2gE96yApOSEpOTF2FQFoJScoJTCfZce7xMqAEopCEop3GdU4FdDC0BSCkJSCgtGFE5JLwBJKQhJKRxJwRnlBSApBSEphSUjCp8OXACUUhCUUjyMfM+nACylICylcN+lx5keBYApBYEpxRhMKQBMKQhMKSwdYV17ht7iMA4LQlMK9xUVvG2yADSlIDSlyEYOWioATSkITSnciV/wsPUC0JSC0JTC0RSc1l8AmlIQmlJkI81hAXBKQXBK4XAK3hdQAJ5SEJ5SWECicFJ8AYhKQYhK4YgKToovAFEpCFEpHFHBKeUFICoFISqFBSQKH/FcAKJSEKJSOKKCE6oLQFQKQlQKNjJELABRKQhRKRxRwQnVBSAqBSEqhSMqOB+5AESlIESlcEQF5yMXgKgUhKgUjqjgZN4CEJWCEJXC7VCJ1GZAVApCVApHVHAybwGISkGISmERicLJtAVgKgVhKoVjKjiZtgBMpSBMpbCIROFk2gIwlYIwlcIxFZxMWwCoUhCoUjiogpNpCwBVCgJVCgdVcCprAahKQahK4agKTmUtAFYpCFYpLCdROA+0AGClIGClcGAFp3EWAKwUBKwUlpNonERZALBSELBScMf2cCQCsFIQsFJwl+iAIxGAlYKAlcJyEo2TKAsAVgoCVgrLSTROoiwAWCkIWCmEW0bEkQjASkHASiFcvg3KwiwAVykIVyksJtE4A7EAXKUgXKUQju/hSAZcpSBcpRAu2QFHMuAq57/95zdvqv1r2RzLzS/7TfnlzV/+8Y83/1V+KdenY/nmm/9581+V+zPL2DdW681f/ucN6yrSX/7nf//3m7OG+dc3F+/2NyN3dtR+3a9DZ9x3JtKc7VafynV3UbMqd9XxWDa+S5VdPSqZ7nBTvlbrEjjk4uowsYSrx7bedrd7rHbhs+sayauvrj+9yVm9rderre9P+jdrNvUn+Vsfq3pvrmp9X6ILuosvIbNkX6+rMEC4zL2b7GaySY42m8eVefJfP6+O65fwDTD14EVJnhZyncfytfsD9Jf5/hLf6WbTlG3wyMwRiddY65rDG/yED998NfxaouzBXWu+EJ7o8rULkV0J7rXw3mr2kPwy0FPzX0JfQi77kmr3/0q5/3fP9Js3Wd4bZEX/CxP9f3B1vkvW/8V8RDiteKadqtog6qT3KmTiY9t2boLIzYKqnhhn220Y/Z6L/sZU/3RYoVNdVvvD6eiapCBQuPLcJ3urT8eIOy86UuO3c/e53DxV2/L49RC6MylmF38miSzZYVclqn8GL9TkiFx93XCvn9ttWR7C+u53WXlap+Bc7U7bY3XYlm25LW27GRSR+0Vkic3vdvu5u77zHbwInvlx01cfnto27R6r7t/b6vnlGFYKL6DN+UVJzg7Vny25US9MdGKRDodyvwlaotxviRLf5+FQ7Z9q341flFQf3ftbN9XhGA49hD/0SAyKq6+npt6ZShD6lL7PxNb26nM4PFK+v5vv1/jD5dS+38SK3/mt1itaCTKvyrsa3zX/xc0uu/plf/JHJN7DFMkO7RWeFy/qEn20h66qN6ZUYXuU+e1Roq/jcdX1oxvU9PqNB1eJ463jsake6Yg897uth/4d6NTwO7sEI8LcHxEmjlbP7gJXhR8kD3lfQpFY6c4uX1fbUxmWsPBLmNhhnzZV7V5I+D68h5jq6fhSN9U/bQC3x9XxFA7q8syvGom193VVbVePXW3oyhiONv0hjjlL7iZ37WrXNQtdVNMBgNc1iiwxCr8EL4H77yDRAajuZlHdmzf0Y6YisUyPq/Wnp7r5vGo2z2V7PDVkZOIPsM0iXKrP56Y+7Tfrbu4VzjIF81uDtJ71cbVd7UnUaf/pZWl17HHVlkpsynUXIkHAcb+LTWwynbNyP3Tm11mReod2Dkf7bKb8aX6e1jA9VuH4oSuDVyDZN3M8sdYbby/18VP5NRhMeP1g4rjQODI9RFA06bXlmUqrmo/1JiiL+XjqdQqT2Nw+1vs/61MQmtJ71jIx0E2Mh42N39splfjGTtU2HPJ5dS7dA5l2Fn4/maWWZL/ZltUmbF98R6lvu3fU/a16qsKSZf5LT3zn1t1hdXwJHPn9RNbHdWotOR2PZLDuN8gm9zzdzf60ewzvUfhLL+YL6OnOyMzQC+78fJNmf0aKw3U3aTKN8cGunGzCAnpBJkW/3CBVWuCfHTddf7SinrV/6+dlC/Ol0lTP3bQ7dOivUSS2W26dM3iUXrFU2mRsbbqdcOWQB17SKoNx81LX3XOqmm6I3A19SCfrT2LNDq6bnJpJCnHn97GJq6Wdu+favNLAU6783j+5YM91P6QInWnfWWqxDnTiZD5V7YVD6pu0fljoSPuOUt/lwQySqt3qORxS+w9dJC4ZrLt/lE1X5ddNWZKVA78PSBzfrF+6R9+Nbk7hAJExfxQhEh/Yy6pZrbvShVMbfwVY8tRidXEfdgBBD5D4rF7K9afVupsNttVjta2OwSCA+eNKlsgvrMthQ8H8joAl9uHWlwENNFy7B+57S2xfjbddtW7qw0s3xw/9+Wslqa2q9Vef2hL0Mdqf6t9wt/va9O3ujtuwiP7yS+JivHXpKkLXSNbNpto/h079tRed2AG+dOOiroDWhR/H/hhEpLYhxlkT1lPhj0FEahti220yL/KW5xLb2apZb8nSrz9YEIluuh48HDj6dIaJxIA1XtZdHNRhkbhfl7hOdVa3Zu4d3pv07y2x5ekchV58GGPObHDDKde+Gvxy/kt+/o+i/w+TDpYsCR+Ev9ikE6utcWaRRjiQ8Z6pOVEpyVW9NSvxz6vmkfRc3H+yXCfW1nr/ZEb34axc+q2wSm3rjKtn2kV4jlJ7P+tnMEfwnlXqK7SOTnYlc39u0gl29HubxJWWwG1bHlFnkRV+13PTjZ8dd8PLcD2i8PufOY8AMM3MB/IsS2w/h7XCq42JDbq5w+ZkBtFhDPtrYOfKKy5AmPdLp+ICT9X5Lxfjom8EZHaeDLF+uiV5f5V0g6fuP+T5pzO5lfr8U9Ffrs6zNXVe3ldnP4qfua/sRdW5YEqdL9fny/UZh+Znm/y8Enwuqs4uq9fnv5ybMi3OxmfPWp2N896zPlNmcw5O3yQ+nP+jv9ycKeD+44xnzR6qvrU8GxfnCeplGTKR7pn3egoBhL/Clyd7OXb/vq4/hkuZXqU16YCJHg00fznutmYp40hmbpm/tpylDhXrw9dwOBysY6Te6uHrYBJivi7u0fzUpvzwtTEE1IznwvbcR33JlbzZl02z2lThor7yx4R56iSETmXMGbpe5sgl6PU51hNvuSlJ8o3yHpzu60Cm+mjOdF9z2MM5I4H1f+GXdaes/4mzxCbWlmFXb8LUpEz6waASewDrqzVDsKDzk/7TSoyrbspxKDc0Rs1n5z1Xib5OTTdcPq7a1uSd0EmCP+RleeJYwXkczCf90UJqd+xcuYSRVVfI+tQQxuAvWIhE9tG73a6+klWszCdGWeo8y3nblceXOlzU91vH7Lan18WcXZMNJ4F+BspN7vokmcgj9FFoapvr/DpvFbltv0VKzHvq/dGkQukv/+jUfsr5gpko3vvlqSsQp268tgsXpbwnJmVimHzt5l+wTP7sK7F72qy+hhW18HOnWFrLvSkfT8H03W/VEj2st6uuXTOZknSxx2+tWWIUbMqn1Wl7LJ+eumkQwNhB8uUtHr2Us8Chj9jTgqt36GedhdTeR563eKSTIuXHRZ7YYfW+juWXcDbqP7k8kXRsym15HPIcf2KbJc5+NmX76VgfhmOhoPMrUsvVzS7qEC/6vYA8D53lZVB+niRo1g8A8vNoIT9nc5qNsUnq1WpbB7WG+4lRPHHUtKkGqydC++u256xTmbiK1jk8dB0azRDyy3aeiGSJE8zO5ZEy/Sz3e8jEVKizo6dqS/LPpZ8EplKjqV49HSlI9ZM9WVrD3vkJ1+D9LD7OElvieh2Oob0b0onPuS67+UvYevpJRTxxWLOpd6sqXPlkPvBIjaS6Kf/71FWyMI68+8oSV4029amL8fW2Wn+qDER5DYfRub/OlxhJ1uO2fDpar4E3n88ldg5m6lKFKc4+9uCJg6GuS38hWYjcny9ylliek0sZDJsFP0FVpvYp/bJQOJbK/bHUeRXgIa3BKv/sumSXiR92B/5gL3H+2SdIrY6Hugrnjv4ENHGe2Dvb9Gmh5Ka53zCIxEGD2SgTjLsDvp/mYj9s3pn/HvNz836Lv757f6qbroKGLYbwt/KIIq3lcZlRyF0m/b0ViQSLJEUrnwbliRy+3L9WTb23f/OD128QdWJLVjZNuATprwineWi7GUlXITeHpn6mW2SUP3EqEkdoJtHzz7Zz1b3HcOWL+84SA9VsAjqugg0BfpglggLnhm548DM68sTH9aVc/0lyE72wLBJTYsov3YAhXMPzF82yLC2UTNLFoeslyJY3f8jBE6PSuDodq7BIfo+YmLvV+dmGVcQfmItUJ/vNY9NNI22TYDv9MAEg8yf0Ki0urdPB8NHfXJLYCDhHTU1bP6/xS4sC5+hYHYknf+59XthLHJA4l6dwvcLP30zk4MaPm/sNH5mfXJiIQH13pHA+rEvctGW8dX84VcdyNywe91OseOIAPnRJp4TcTzjhiSvaxmVTPncV3Y1UYBz70/PEdDDjt+2GmnRLgvCpskhc+jHO3JJNeL/+S0lcZ32qQuSn/KQEnThgfdqunkmujz+oSEztf+r+QDoy79kUiYM466XcoL0tftZiYg1wzsCzDnYon4EgT1z9fKrDkpkTcT1edV4DSMyfeKprw19Iu+bfbGJKcjfgKqO59/4ab2Ka+1NDK7k/kxXijCSLSwrFZS9TYtw1Xe08HFyGb4gcPCH1kBh/aNeWH4L8IbF6do5o+yb9bTMqcXJjHNFWTfrpR+qGEh3CFpwFu5+TvbRfd491mNbqtxgqcbuzcXVqiB+/U0/crNj5MVCiJUmL3q0lVvRw65Q/hEp9xKftdhDw0p+uqMTZz3MZNg7+9Pi8VHZeS8wSa0rnc7XdvqxMRWnarqK365eSVE4/XZwn5rV1fvvJX+879OivQCYmuHUe7aLM04qsYOd+i5aYDdY5+1R+NZPJXTgbyaS/Xpg4Fu28nUcbZIO4v6HoIa0yGWc9TBuUzV/KThxfdO4GIz5/F4dMTBvr/BzqhvSb/gJw4tyt84NGKP5iwENa1QSp5X4GUZGIDXBeuV/Ti8ScZNNFHsKdO/6T1om7DMJW3d8oo/IzF0icvr2sWpK45q+SJA4jOidmrh02pH4ybmKv/1KuNttqTyqvH4oy1VGYdxtsssoSb6rakGmGv8H5nMQpz9tjFTsPRRIngy+71Xq3kWHii5+hfoOf9mWVhY588Jl4OkzviJkD731XfnOXOPjtXcmMha781ik11uvdZQMLyV/yIzX1pXb9/aCx8zcqiMTVy+HmxMyfxmepgVqfwoQI7ieV8MTVpZdw7uM1B4mXRw4L4P4t8cQVs85bZMu2TwNF4v6Lzhvcfey3viLxqIWXtt9/OUxZEj5VFIkn0nj+mgE19wfJInEx56UdbgsR/iEtIvkdgGR/4eN3kYimO090Qif8XDGZOLd+adHKrgjOAUpMhrm6sv8f+gsm6qmv8exvWKmFP4SWictVLy2dpQs/b0qmNuwtKI+/NU4mrvl0jo7HgwlSEhD+ar9MRLsvLcj/9O8uMevgpT1nooNEb+lXR5WYm/rSmiH246oxo+zQmz+VyhJb5nbfjUPr5tNUUrr054wqOeZ67wey30j6UymVeCjIxZtJXHpZDfepSf+cK5U6Hmj9rVahO/+BJreW9bqpH00YDh36Ax+VOG+xDofYSfpbXlQiV3tpB+BW+uRW6dSqZkYqoRt/9SZxCvTSDvdmSn8QqxKXCztH5KAu6UMwndx6tzSvXfr7YXVypeqeszv4yk6FAoe5v78o8ehGz+Gg1vtNpU7kFp6/AUCWfnOpU6dGbXtsaB33Cb5OjvYjncv6E788uVIfV+2nsDT+bSUisRdDkcleQn/hVCce2PBiYMm+3fa7k7poJacj+B2BLlKdnqrBaYHKRy954kqL8TRMj1Ms2COSWqVPFca35luzXjJGalyZxaQvx4NZniWZkX6OQmK+j3E3XHRRfjZpnnjo2ksbPd1S+Yk/uU6tkp/Lx66p/0TWNv2RWZ7crl58dd36HpwRGCTGJJ7a1HkdProg1yDxWFUzTAuX8/xUpNTRXufkfFBGuKTqzyxTmws4cMx8RpclHjFYmYFU3VBMIv2tkuohLVw9X3ThSfq7h1Ri5SRHz/hBILJ+pUe5ge03b4pEPoqPoRF+soY47/UR590/4qwiz+tJUl929p1Loi7Jv72NPu801OetglqeN8eddwjm+WWXXFrFG4zzlT/xyxOXgqr9envalO2h7Brk2vxv+DT8ZDZ1fgiJcxF6cJW/7SDZQbPrOp/XcpBg7hOI/Pzo88SFXpudbw7G2JdbcoKbv9CQOPwiu4VChz7cEInTD+twdzqWJO790ExMSbKuhlmU3N/mIhIXo6u9PcxxsAnfHy8ViSkBlTnir2sFq/2KrBv667hZItu4cCWyIdtf5E5+YJ2r5kQ6bT/pVCciKpSBrHxYrBNnCdUhPB/Nh1JZ4k7/qrV7ZsjZ4n4aTWJCdOfocihleRwEg/BZr0jcqVS1Lg76oAjDPvMT3LPEkUTVmqNqnulpIf56FkuNrdZtpAyzpHz8KxO3P1VtZKXcX5lOnKpVbZ+gGy67+o2NOO9GP29LleKyTyWxmWzpcCDz4zdLPJO6c+OybYIn6Oe9C8HOnXfawKdzedpu0QlJPvZL5JBV+7w6dmNhOg/0m26dOCKr2pdqswkLxX0kzRMzr6p2cMQH9/PpReJMxPg5heedCP+4MpF4KnbVbqv2WO7JQ8p88Jultozttl7Ro3yU/7iL5Cq1rT8f6s9lsyMnbjJ//whLbjZ21b7aVf8MY1X5vWWRmHRUtW7LXvgG/QqaXNUPK1p7JPOX+BJ3EroNWzTK/SLpxJzyqu2axA1t+7PgDMdEXNC5Ou1pVHF/MY0X53Syc4umzwdk6EQcWLX2GPtDY1FC+CiZ37+w5NppNphtaNKBX0GLxFSwztXX3bbafwofpU+IE7O4qva1q+20Q/bXlsXlGBJ2PsEoMQmqaj831aC3z8ITedKa2z9Xryt0grz37FjivpmrK3wwuxfaLLGSXF0Ozo8PvtmRuC8qdAdLGeTrJS6E/tl2f2oHO3j9qpw29OqTqEKo5vOixJXe3k84/vbP/MwSvzTTOWrKQzfg2pRdY+W78zeCJi79XJzB3YD+/pe0t9n5M1uBP4Vn4vsbTtJe38VP8LzyIPkpzRHZ3sH9xkwktkDGSRF6+f8ru5blyG0k+C8++2ACfGl/ZcMHSuKoueomOkj2aMYR/vcFQILOKkDj1M0ex6TZJB71yMrE7DCxljsyYH6fZiUVjPRD8k1fffQ+FkYxsLdNdrauwyOIoi4ZC10oYHLve1fwUKscE1by/igPlGLsyn26q7/QZIKJsWZPknjy2wczTPbVeJBwwU7jhxrIwkuRPE5CrCmfCMPMPTj8/TdLZgt75Ormq2zWY4TY0L/Sb9zx5bGsKpmuxOA7ORAewuCgIiXfF8bBZFU/ACnWdYcJ1hPZqo6maFoTxSKBwJKszB3JJb81EXJifbpjv2FJGA/Jh1WKbRp7VmTJxeaSxqiMC1FalLxwVCsKC9Xk33fvj3vBHa3C28qQJe4drfzmUGeJ/gROsWPx/XdkynYb3uaTtlByl+hwkv2JJI/dhsmvtnJjBVcvWRbXugYGew6GHGILIAWqNBahLBkwBE9FHzRkjCqhns0dFQj1MW0XHf6JGWPu1AiQUUc4fz48y9gv+R4m6931+nEZx2sGiYxs+kPIvh0yHSuy/nEL/VKfppbMEJAURO+CHS7+NVG2ACj2g/6IJQuxyKRzHheUZHRnvHPJsZHbzvGSZw1mduQY0YHjPmbtNglYLNS66lYZDvn17CeLemsq9sPaNHlH3KbX10OkRKxrPPXIDzbN0+DPz+mvrCeDBZSe/XZH7UtW5fCxyB5KBHrc3Pp9XDRlpBKyLiyctsCy2JCxZNfvNgV5BvdNxiJIayILxjvQujnJkBJy3WSV8PauZQvFC2KXuDrDG3SNbdmL4RhaymZ+cZGTWfzNzZNS462xZFmTuWS8VUoBDMq2VmQ4dHM6ZMcRBVLzKIBsLuRvl+H6TZ65wk6Uf6bg/fF2KeChxBRZ6cy7xr0QiOMOFn0r2V5oDCS55MRdqJMxbZMkg9v0Dx15iQVweafi/9L+kQSVyZr5QbiV1xBWA0kmy4FTmu8XA6Dcx5kViaERArNktSaAbH7BvGmnbiHDwq0+ZBBncix4/ZNCIRFP6oqhjoohb1qgISsfLeRJk01M96KMlzEaIQkZbi44Q2Eo0lfHVuhJ/oObswCgxTpZTw7VulkPwtVWSFpxH87DOMUiazFP6clOvj/25+/DVUmK4EFWk2lAENkfXnfzGpkdYhmYdA4NDu3fpzcldNZhXeOJbDmcUEFCZHyZdHzTYWTyRDYd3BzpzPmvrVFHsybTnUDVvSqeey2UR8n4MgFlTs1CqIldqOtFJsI1ThU05B3u5lgULq0LrJ6T3Rl3H17ULEaLVcGe1Ndwd1U7woaxJaPKAFL0CMGwgtS8D1iqHmjxvLLsft5xQp0g1+KwGNHZL7yqImO4wpi1IsMnt7yOS5JxUSrHOBzJ3hX+Xp3UWAdqYJDzfW4tNjixz0emLDuFoMhUxHZYTXaItSq3RMTKSk3OtvoN5L+jvKXRuK4lI4dQ89SEEGRE9ykC7MnR3fuwBCqZ2AIGc2xLhpIeSFWgaixQ1uTU4X1Yt/HZKcaAEYomNNR2+eaWYiVK2GF9Ba1E1sbJB3JSIaIt7vbs3PttUBE4tvirLwCun/1ajOi5Ky3BlX6u8BBnl/92KTc5KmHl/oWn21zx3SH5oKKfTjG/GpSjb5Pic7d/itDhJR9zXIJJoSqqGcyIDHlReajI8c6CjBp7kDV5uXi02xSnlJT1HB695ETXXRve4vWZDMDqk9DfnQxG8sDTRDpkURuyMna/Di/jxWmX3xp/b0N2d+6KbtFgAt6xC1grzGBpvCanNO9unbLlgGF/nZxp2+Qo1CcPlidSXurutNw0btfkstSQdJzIQJR7AVsCJC0youR2GaYRxzD5NXeqW6S9yfo5gpFkjNjWd5I80QjdcZJFdl+mm+L7G6RPGDIxOXCKclIV8g0MyZL1gPN2mcYlKE8ojxskQ3FgyuMFBTArMhLN5ZZR6KUhU4plmJTVoSBRkafMMnwUdCDRX51kF+D8e4ZYYfhpyMkwgeiWUuMc6RSGjPnKsPdhUqUkfGKytKqgS4o3BuNLQ/JoETfui1mmV+YPoZ3HbXwEDfyeSOqQqEhLIAmggTssYxvsx5L8kgASEhkZTeMdSsq5ByDNwTEi8iUFQQJQNpRnRIxKDhEsh9CWXMiYKlRk/nggqVBSuF9yZ1oAWjbRnzAYLxuSWBFw8pF7gymjIY/ZAKVqHAbjW0O2PQPOz3XT3m9Ipu3JxD94FL/N01/ZuKLBuRlDhu9hVmiY33RnF4e0SQrkMn7zB9jl5eIylWKpk83ChdqsLFJhKSiNsj6R4dMyhjaYT9dfx+v0PRR05LvDnj/ZET0h7+OcmUajNJkh0+Qd8HnY/NH6szA8b1qRjH7lh5dYSw1e1B29YALczuwpPCHSsQ1JMN4hc6UjNA+oyAxjxyoYEmKz+isv7lMlgwrTjorknO6YBTQrqkb73z49X1P+d/REq+SVWiXXU5P+xDTJHvIcpD7RyH7dTmaX9FocuunIIc7Db2d4eQmaHrkgkUFlOUO2ng/QXCPNoMaOIQPgA63U+zcYkxtyGP3Au03By/LiZpVi4f1DKiYciJ8b3iMV25C57wH6K8t7pPYYcszDn/4lkhBqdJBWoB7JXb+reBWT3TRZVJPFpANwHa7TsMrLqcVWZk+f/HsKnfnIIdmDPfODepWivCLJ5/SapUMN7WfcoOpfe7oyp4OhI8toy9uzuNWx/NCwmUkgoeS0NDxJSVLTcsuM25EcT3LaM0cPzDVqsq+wuC2XM8NaT0s2VZeH6vBhe4l9L495yKbKkMlk2U+Vj0y2WC/tyMLOgQP6orIjhI/GHdvrcLtf/fm/Kf4QfjoyTVyHQI3KBGkweGvJyGN9cbqzgfxYUsGwMCOAwpEmcZ6eSHLRznL279+HvdsgJZGRGdSQHHiJp4QycdaFZE0AC1ucCLiXSdJSHvQZnHaypBHjDrM+nnV+VaN2cUNux9Vfr/OrD4Dml3G8O/l8FvkElsySC7wL6R5ELrQIM74umjCBpzr95k8s/2s3/59U/oeSrKRL9o55+4XlD7JWyIaIBs1Nf4R3LrkllENcg6yANsXhfeIv9iRVdo1JparztrhiOrJOv4Z/wQfEylNL5s9rCBqVb6pB1r0lJ6FyLbEG61ct2aBOdMmCREmFB6+hN2rEyxiKIsohz7RcxNAiMcOSNLB1VMrGWJ2vEgs2pX4dqTC9RjMP93HqxIRxQ3XR1xgwNGR8GICTbM/34fpQmj3YpKNf5HbIa8uHw3OY3gNbqQRSY3rSmMQA7o932iZ34damP0n6Nu2Zlaf/1KXcuycTpvBMhWqZ6AbRl9YeVRfLPJWofbC71AO6tVg3arHI0/f8j90t7JWUmaQHIeuFDQdPZE09ktDCdI49FLZ/c2/HxViTVaD11743eKjyO+XfTOFx/5HZ0T+onznDWwzUarJFF2DT4bPjiN0tDlz+Ox1/tjin/GcwyiUH8TxetFktr36UQCTl1TxgVDsOidApbSY2Ka78jmROetQggyk3O96lJG92/cw1CcXtGlLPd42uSfLHYTeo5fferoQgCyxYYSEr4B7pNvx4dq8/tRJ2jYSYhj/JQgQpfyCKl5NFpIgTxwbLywyZiWTNNUKGCUL5zpASR9bk12gwpUbqUbOajrgLzlJ45/Ib6NOhFKyW8UsiUqGLLx7HGkmtjXUfsFK8XmG+RmcT231Y1w8nSZw1UgwafjloslSDfIKG/3UFVk0jpIDYesRYUFXHq7kjaXgeKFZc1CmKBSr+7lz9W0pe625RkLi8yF5ohAwRyKR2IhLASPmVoIB5XaMH4/vLKu2UGmRxNGSDJwA65yMFOVmKBImWbFh6qBjphxTis3sNE1ay/u9h/xHpLkW0yDNpyDpkbpCFNSZyFKpkjoWztOzFXTDGwouN3QOX8arI56hDQbJ61otf/S9KccjgQK4lB2f09A3mCd1BnjSJCNycWtbpT/pkpNantKs3iXtpj2yrJ8cgs5se+0d1YiU3idvZ9qdWHbnD5+EezHnEshS/lwXSrhoGDwnLVuDiaXMd5reHliHAWe+OHIxb7z4SVJN6SFUhO+gBRrcQkKjYk9aZpyGHLD7hWmevn21YFHES911/dNgbcy6QsxKQ6i1pJbYp3e9OLfZUNugSdbsnWbnxsfbSf+hIKEoF9o3ZS8Mfx5JLa3F2157uyeyBFfEKPibYPW3ZY0uJGlQYJ1WJ2FO3xxuv//kq6ehI77et0v499Zias71p0+c5v0o6Q0hhgPCcw6v/HFsQuFX+LZjQ0GgFSdruD6HIxmMd8ge6cofVg5otjmXf1WIn25J90Fy2sG0xVyaHInaYj+lVCU+ioldPOmGs20/FR0D6Zk+Sk9fHc8G2FavMHTmE65HKDqcY0LBR0uM5b19jOYa0XF0ftyy0R+2aluSmro95UVTwChtwhr3LHrOqfFcoQWXIOYD1cQ/Jz/iabkUZ3yClySQqhCVnektqujj6WrGVsJ+rsqyq8VZr2GAnwuRzGFhCMGzbaccKUYl8YbhELZvMRjC/lceCgafwkOQebtN8ftzNFdnC3qLsZzlWwgoHSdrQZloGF6utuAM9gDw/Jj1kZVBPxJLKSP6N36+KHNFg+Nuwv8wDucUfDWVLAbxpKrLdv4XhuVnToPEK7MiSb0Ka3LyMw6rUA/4QmceXEfPwqcVMuyPZe5pB0CCDoG2PSKXtUrTYcqdG2fTLYpvHkt50wZLgNlwzZrrBAMeQzPTMD85g7cSS8yCZIK9FNrpNQVx9Gk2k+K5NmkFPVfoHsv4d/5dGHsO4X8gIL8JYCYPNBzL+iTBS8x0FxHqyz7s5vy1UfoprmOSJbO7t7Tp+4oQh5a3Z55r9tSzJ2XhRdSRBJNSwlApgh7ytp5p83S6YKKjnwTIi2YLd3EOyeyqkNVRkz39zH6P+aliAZO+Tw1JRXW/IxSVrOmDOKE8bHGRnT/+AFYKybCoet1tNyiRvRX16scbJx/qx7SxomUhhKE129PXvqjEorFMJrGHXgkfLmic4KFD3ibCQ9NObM7FPIW2bpgja5vSOSxSGpK3WkSOxGTnGILPYkLWExyQXEpZxSDLSQ83N4zFbJ+XummwtPaaP8TlIisujDaV+SMrsIxPKslgSrMki1WP+hXMZninkvfyYy6qbKCJFDq2qWbhWCOWSfU+PkQnuWuw+WDLh9ECxLaJJ+DgzWJGJuce6hxqcfNk4M0pGkY/1Wf4wjODJ9tFjHRefmshX1KGo3FPNRTaPLCm0GGxbkrDyUBuuwSpuS54eOScMH6VObpXd6cBDhsMRN0xQpwaUrNJgSkcWss6elmplYZpCxoQldVpR7eRQds+dRelP1djCasiO/IFVlLPCtZqyEksWDgoGkFj9qZNDXEceEzue3JB4+VVkreZ77pqNugI9aXctbocGqZhtn65RMgL+GKbtMW+TlE7D2NWSBK0TafwxKZ4wLnuS9RTQPi5qFsLisWPJutbHsEgmBCxTEiBOSJYsdYxUQifx8hveIlPKpqmontQx/xjHd6UWjXBkKSorctfYTW7IKltB/x/5SDZlypY8s3a8Ybu7Sd3SqKZoySLIjlaq/4ma9xewgrbWcJe3GqoRWXIO8kBzc57ZWlRCsWT0v+Nl9YsW52x6UnQwqCG+LoM8dfB8btmP6Zb3MK5TKuG1yKPo2Le2TEqFDEe4KjKCjyiZtga2HQzZTYxImbiGFR4H5BEfkHJ1DWxxGjKCi1Du+X/+nauECTsZZKMngmXCGDg9TfYJIlBJGQOLfWRvP2JpaQw8Hwy5QAX7t0EaTNud7Axuaf4IIeCb6h1hilqR/dUIlPlD4eqsyOpSRNqn/iUWko/ISyxi6dYYrs6KjG9lrw+nx9ouFaVJMuxfhegKB6qZuf4/f//tPt3H2BT9z3///Pvv/wP01i7l"; \ No newline at end of file +window.searchData = "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"; \ No newline at end of file diff --git a/docs/ts/html/functions/hs.mouse.absolutePosition.html b/docs/ts/html/functions/hs.mouse.absolutePosition.html new file mode 100644 index 00000000..3cab65ae --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.absolutePosition.html @@ -0,0 +1,5 @@ +absolutePosition | hammerspoon2-docs
hammerspoon2-docs
    Preparing search index...

    Function absolutePosition

    • Returns the current mouse pointer position in Hammerspoon screen coordinates. +Hammerspoon coordinates have (0, 0) at the top-left of the primary display, +with y increasing downward.

      +

      Returns Record<string, number>

      An object with x and y number properties.

      +
    diff --git a/docs/ts/html/functions/hs.mouse.count.html b/docs/ts/html/functions/hs.mouse.count.html new file mode 100644 index 00000000..29b2a544 --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.count.html @@ -0,0 +1,4 @@ +count | hammerspoon2-docs
    hammerspoon2-docs
      Preparing search index...

      Function count

      • Returns the number of mouse devices currently attached to the system.

        +

        Parameters

        • includeInternal: boolean

          When true, built-in pointing devices (e.g. the MacBook built-in trackpad) are included. Defaults to false.

          +

        Returns number

        The number of attached mouse devices.

        +
      diff --git a/docs/ts/html/functions/hs.mouse.currentCursorType.html b/docs/ts/html/functions/hs.mouse.currentCursorType.html new file mode 100644 index 00000000..e364e11f --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.currentCursorType.html @@ -0,0 +1,5 @@ +currentCursorType | hammerspoon2-docs
      hammerspoon2-docs
        Preparing search index...

        Function currentCursorType

        • Returns the name of the cursor type currently set by this application. +has the keyboard focus, the visible system cursor may differ.

          +

          Returns string

          A string such as "arrow", "iBeam", "crosshair", "pointingHand",

          +

          This reflects the cursor set by the Hammerspoon process. If another application

          +
        diff --git a/docs/ts/html/functions/hs.mouse.getCurrentScreen.html b/docs/ts/html/functions/hs.mouse.getCurrentScreen.html new file mode 100644 index 00000000..240381a8 --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.getCurrentScreen.html @@ -0,0 +1,3 @@ +getCurrentScreen | hammerspoon2-docs
        hammerspoon2-docs
          Preparing search index...

          Function getCurrentScreen

          • Returns the screen that the mouse pointer is currently on.

            +

            Returns HSScreen | null

            An HSScreen object for the display containing the cursor, or null if none can be determined.

            +
          diff --git a/docs/ts/html/functions/hs.mouse.getRelativePosition.html b/docs/ts/html/functions/hs.mouse.getRelativePosition.html new file mode 100644 index 00000000..841f4a11 --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.getRelativePosition.html @@ -0,0 +1,5 @@ +getRelativePosition | hammerspoon2-docs
          hammerspoon2-docs
            Preparing search index...

            Function getRelativePosition

            • Returns the mouse pointer position relative to the screen it is currently on. +The returned coordinates have (0, 0) at the top-left corner of the screen +that the cursor is on.

              +

              Returns Record<string, number> | null

              An object with x and y number properties, or null if no screen can be determined.

              +
            diff --git a/docs/ts/html/functions/hs.mouse.names.html b/docs/ts/html/functions/hs.mouse.names.html new file mode 100644 index 00000000..3cb0485d --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.names.html @@ -0,0 +1,4 @@ +names | hammerspoon2-docs
            hammerspoon2-docs
              Preparing search index...

              Function names

              • Returns the product names of all mouse devices currently attached to the system.

                +

                Parameters

                • includeInternal: boolean

                  When true, built-in pointing devices are included. Defaults to false.

                  +

                Returns string[]

                An array of product name strings.

                +
              diff --git a/docs/ts/html/functions/hs.mouse.scrollDirection.html b/docs/ts/html/functions/hs.mouse.scrollDirection.html new file mode 100644 index 00000000..b3ca8c93 --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.scrollDirection.html @@ -0,0 +1,3 @@ +scrollDirection | hammerspoon2-docs
              hammerspoon2-docs
                Preparing search index...

                Function scrollDirection

                • Returns the current scroll wheel direction setting.

                  +

                  Returns string

                  "natural" if content scrolls in the same direction as the finger/wheel movement (macOS default), or "normal" for the traditional direction.

                  +
                diff --git a/docs/ts/html/functions/hs.mouse.setAbsolutePosition.html b/docs/ts/html/functions/hs.mouse.setAbsolutePosition.html new file mode 100644 index 00000000..2d4e2165 --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.setAbsolutePosition.html @@ -0,0 +1,4 @@ +setAbsolutePosition | hammerspoon2-docs
                hammerspoon2-docs
                  Preparing search index...

                  Function setAbsolutePosition

                  • Moves the mouse pointer to the specified absolute position in Hammerspoon screen coordinates.

                    +

                    Parameters

                    • x: number

                      Horizontal position; 0 is the left edge of the primary display.

                      +
                    • y: number

                      Vertical position; 0 is the top edge of the primary display.

                      +

                    Returns void

                  diff --git a/docs/ts/html/functions/hs.mouse.setRelativePosition.html b/docs/ts/html/functions/hs.mouse.setRelativePosition.html new file mode 100644 index 00000000..1a9ac120 --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.setRelativePosition.html @@ -0,0 +1,4 @@ +setRelativePosition | hammerspoon2-docs
                  hammerspoon2-docs
                    Preparing search index...

                    Function setRelativePosition

                    • Moves the mouse pointer to a position relative to the screen it is currently on.

                      +

                      Parameters

                      • x: number

                        Horizontal offset from the current screen's left edge.

                        +
                      • y: number

                        Vertical offset from the current screen's top edge.

                        +

                      Returns void

                    diff --git a/docs/ts/html/functions/hs.mouse.setTrackingSpeed.html b/docs/ts/html/functions/hs.mouse.setTrackingSpeed.html new file mode 100644 index 00000000..2a1c6de7 --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.setTrackingSpeed.html @@ -0,0 +1,6 @@ +setTrackingSpeed | hammerspoon2-docs
                    hammerspoon2-docs
                      Preparing search index...

                      Function setTrackingSpeed

                      • Sets the mouse tracking speed (acceleration level). +The change takes effect immediately for the current login session and is also persisted +to preferences so it survives a restart. Values outside the valid range or non-finite +values are rejected with a warning and no change is made.

                        +

                        Parameters

                        • speed: number

                          Desired tracking speed in the range -1.0 to 3.0.

                          +

                        Returns void

                      diff --git a/docs/ts/html/functions/hs.mouse.trackingSpeed.html b/docs/ts/html/functions/hs.mouse.trackingSpeed.html new file mode 100644 index 00000000..4d95912d --- /dev/null +++ b/docs/ts/html/functions/hs.mouse.trackingSpeed.html @@ -0,0 +1,5 @@ +trackingSpeed | hammerspoon2-docs
                      hammerspoon2-docs
                        Preparing search index...

                        Function trackingSpeed

                        • Returns the current mouse tracking speed (acceleration level). +Values range from -1.0 (system default, acceleration disabled) to 3.0 (maximum acceleration). +Returns -1.0 if the value cannot be read.

                          +

                          Returns number

                          The current tracking speed as a number.

                          +
                        diff --git a/docs/ts/html/modules/hs.html b/docs/ts/html/modules/hs.html index de60b263..9cd0aa89 100644 --- a/docs/ts/html/modules/hs.html +++ b/docs/ts/html/modules/hs.html @@ -1,2 +1,2 @@ hs | hammerspoon2-docs
                        hammerspoon2-docs
                          Preparing search index...
                          +

                          Namespaces

                          appinfo
                          application
                          audiodevice
                          ax
                          bonjour
                          camera
                          chooser
                          docs
                          eventtap
                          fs
                          hash
                          hotkey
                          http
                          httpserver
                          ipc
                          keycodes
                          location
                          mouse
                          network
                          notify
                          ocr
                          osascript
                          pasteboard
                          permissions
                          power
                          screen
                          shortcuts
                          sound
                          spotlight
                          task
                          timer
                          translation
                          ui
                          urlevent
                          usb
                          window

                          Functions

                          clearConsole
                          closeConsole
                          collectGarbage
                          openConsole
                          reload
                          diff --git a/docs/ts/html/modules/hs.mouse.html b/docs/ts/html/modules/hs.mouse.html new file mode 100644 index 00000000..a45c2b93 --- /dev/null +++ b/docs/ts/html/modules/hs.mouse.html @@ -0,0 +1,16 @@ +mouse | hammerspoon2-docs
                          hammerspoon2-docs
                            Preparing search index...

                            Namespace mouse

                            Control and inspect the mouse pointer and attached mouse devices.

                            + +

                            All coordinates use Hammerspoon screen coordinates: (0, 0) is at the top-left +of the primary display and y increases downward.

                            +
                            const pos = hs.mouse.absolutePosition()
                            console.log("Mouse at " + pos.x + ", " + pos.y)

                            hs.mouse.setAbsolutePosition(100, 200) +
                            + + +
                            console.log("Mice: " + hs.mouse.count())
                            hs.mouse.names().forEach(n => console.log(n)) +
                            + + +
                            console.log(hs.mouse.currentCursorType())   // e.g. "arrow"
                            console.log(hs.mouse.scrollDirection()) // "natural" or "normal" +
                            + +

                            Functions

                            absolutePosition
                            count
                            currentCursorType
                            getCurrentScreen
                            getRelativePosition
                            names
                            scrollDirection
                            setAbsolutePosition
                            setRelativePosition
                            setTrackingSpeed
                            trackingSpeed