API Docs

Monitor and synthesise macOS input events: keyboard, mouse, and scroll wheel.

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

Tapping events

const tap = hs.eventtap.addWatcher(
    [hs.eventtap.eventTypes.keyDown],
    (event) => {
        console.log("Key pressed: " + event.keyCode)
        return hs.eventtap.emit   // pass the event through
    }
)
tap.start()

Suppressing events

Returning hs.eventtap.consume from the callback prevents the event from reaching other applications:

const blocker = hs.eventtap.addWatcher(
    [hs.eventtap.eventTypes.leftMouseDown],
    (event) => hs.eventtap.consume
)
blocker.start()

Sending events

hs.eventtap.keyStroke(["cmd"], "c")
hs.eventtap.leftClick(500, 300)

Types

This module provides the following types:

Properties

hs.eventtap.eventTypes

{[key: string]: number}
A dictionary mapping event type names to their numeric values. Pass values from this dictionary to `addWatcher()` to specify which events to monitor.

hs.eventtap.modifierFlags

{[key: string]: number}
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.

hs.eventtap.consume

boolean
Return this from an event tap callback to suppress the event (prevent other apps from receiving it).

hs.eventtap.emit

boolean
Return this from an event tap callback to allow the event to pass through to other applications.

Methods

hs.eventtap.addWatcher(types, callback, listenOnly) -> HSEventTap

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.
hs.eventtap.addWatcher(types, callback, listenOnly) -> HSEventTap
Name Type Description
types number[] An array of event type integers from `hs.eventtap.eventTypes`
callback function Function called for each matching event. The return value is only meaningful for modify taps.
listenOnly boolean If true, the tap receives events but cannot modify or suppress them. Omit or pass false for a modify tap (the default).
HSEventTap
An HSEventTap watcher, or null if the tap could not be created
event tap watchers will not be automatically destroyed by JavaScript garbage collection. You *MUST* call `removeWatcher()` if you want to dispose of a watcher.
// Modify tap — can suppress events
const tap = hs.eventtap.addWatcher(
    [hs.eventtap.eventTypes.keyDown],
    (event) => {
        console.log("Key: " + event.keyCode)
        return hs.eventtap.emit
    }
)
tap.start()

// Listen-only tap — events always pass through
const listener = hs.eventtap.addWatcher(
    [hs.eventtap.eventTypes.keyDown],
    (event) => { console.log("Key: " + event.keyCode) },
    true
)
listener.start()

hs.eventtap.removeWatcher(tap) -> None

Stop and remove a previously created watcher
hs.eventtap.removeWatcher(tap) -> None
Name Type Description
tap HSEventTap The HSEventTap returned by `addWatcher`
None
hs.eventtap.removeWatcher(tap)

hs.eventtap.makeKeyEvent(key, isDown) -> HSEventTapEvent

Create a keyboard event
hs.eventtap.makeKeyEvent(key, isDown) -> HSEventTapEvent
Name Type Description
key string A key name (e.g. "a", "space", "return", "f1") or numeric key code string
isDown boolean true for key down, false for key up
HSEventTapEvent
An HSEventTapEvent, or null if the key name is unknown
const evt = hs.eventtap.makeKeyEvent("a", true)
evt.rawFlags = hs.eventtap.modifierFlags.cmd
evt.post()

hs.eventtap.makeKeyEventWithCode(keyCode, isDown) -> HSEventTapEvent

Create a keyboard event using a raw key code
hs.eventtap.makeKeyEventWithCode(keyCode, isDown) -> HSEventTapEvent
Name Type Description
keyCode number A numeric virtual key code
isDown boolean true for key down, false for key up
HSEventTapEvent
An HSEventTapEvent
const evt = hs.eventtap.makeKeyEventWithCode(0, true)  // key code 0 = "a"
evt.post()

hs.eventtap.makeMouseEvent(type, x, y, button) -> HSEventTapEvent

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`.
hs.eventtap.makeMouseEvent(type, x, y, button) -> HSEventTapEvent
Name Type Description
type number An event type integer from hs.eventtap.eventTypes (e.g. leftMouseDown)
x number Horizontal position in Hammerspoon screen coordinates
y number Vertical position in Hammerspoon screen coordinates
button number Mouse button number (0=left, 1=right, 2=middle)
HSEventTapEvent
An HSEventTapEvent, or null if the event could not be created
const s = hs.screen.primary()
// Click at the centre of the primary screen:
const cx = s.frame.x + s.frame.w / 2
const cy = s.frame.y + s.frame.h / 2
const evt = hs.eventtap.makeMouseEvent(hs.eventtap.eventTypes.leftMouseDown, cx, cy, 0)
evt.post()

hs.eventtap.makeScrollWheelEvent(deltaX, deltaY, x, y) -> HSEventTapEvent

Create a scroll wheel event at the given position. Coordinates are in **Hammerspoon screen coordinates** (top-left origin, y increases downward).
hs.eventtap.makeScrollWheelEvent(deltaX, deltaY, x, y) -> HSEventTapEvent
Name Type Description
deltaX number Horizontal scroll amount in lines (positive = right)
deltaY number Vertical scroll amount in lines (positive = down)
x number Horizontal position in Hammerspoon screen coordinates
y number Vertical position in Hammerspoon screen coordinates
HSEventTapEvent
An HSEventTapEvent, or null if the event could not be created
const evt = hs.eventtap.makeScrollWheelEvent(0, 3, 500, 400)
evt.post()

hs.eventtap.keyStroke(mods, key) -> None

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.
hs.eventtap.keyStroke(mods, key) -> None
Name Type Description
mods string[] An array of modifier names (e.g. ["cmd", "shift"])
key string A key name or single character (e.g. "a", "space", "return")
None
hs.eventtap.keyStroke(["cmd"], "c")      // Copy
hs.eventtap.keyStroke(["cmd", "shift"], "4")  // Screenshot selection

hs.eventtap.keyStrokes(text) -> None

Type a string of characters as individual key events. A 50 ms pause is inserted between each key-down and key-up event.
hs.eventtap.keyStrokes(text) -> None
Name Type Description
text string The string to type
None
hs.eventtap.keyStrokes("Hello, World!")

hs.eventtap.leftClick(x, y) -> None

Post a left mouse button click at the given position. Coordinates are in **Hammerspoon screen coordinates** (top-left origin, y increases downward).
hs.eventtap.leftClick(x, y) -> None
Name Type Description
x number Horizontal position in Hammerspoon screen coordinates
y number Vertical position in Hammerspoon screen coordinates
None
hs.eventtap.leftClick(400, 300)

hs.eventtap.rightClick(x, y) -> None

Post a right mouse button click at the given position. Coordinates are in **Hammerspoon screen coordinates** (top-left origin, y increases downward).
hs.eventtap.rightClick(x, y) -> None
Name Type Description
x number Horizontal position in Hammerspoon screen coordinates
y number Vertical position in Hammerspoon screen coordinates
None
hs.eventtap.rightClick(400, 300)

hs.eventtap.doubleLeftClick(x, y) -> None

Post a left mouse button double-click at the given position. Coordinates are in **Hammerspoon screen coordinates** (top-left origin, y increases downward).
hs.eventtap.doubleLeftClick(x, y) -> None
Name Type Description
x number Horizontal position in Hammerspoon screen coordinates
y number Vertical position in Hammerspoon screen coordinates
None
hs.eventtap.doubleLeftClick(400, 300)

hs.eventtap.middleClick(x, y) -> None

Post a middle mouse button click at the given position. Coordinates are in **Hammerspoon screen coordinates** (top-left origin, y increases downward).
hs.eventtap.middleClick(x, y) -> None
Name Type Description
x number Horizontal position in Hammerspoon screen coordinates
y number Vertical position in Hammerspoon screen coordinates
None
hs.eventtap.middleClick(400, 300)

hs.eventtap.scrollWheel(deltaX, deltaY, x, y) -> None

Post a scroll wheel event at the given position. Coordinates are in **Hammerspoon screen coordinates** (top-left origin, y increases downward).
hs.eventtap.scrollWheel(deltaX, deltaY, x, y) -> None
Name Type Description
deltaX number Horizontal scroll amount in lines (positive = right)
deltaY number Vertical scroll amount in lines (positive = down)
x number Horizontal position in Hammerspoon screen coordinates
y number Vertical position in Hammerspoon screen coordinates
None
hs.eventtap.scrollWheel(0, 3, 500, 400)  // Scroll down 3 lines

hs.eventtap.currentModifiers() -> string[]

Returns the currently held modifier keys
hs.eventtap.currentModifiers() -> string[]
string[]
An array of modifier key names such as ["cmd", "shift"]
const mods = hs.eventtap.currentModifiers()
if (mods.includes("cmd")) console.log("Cmd is held")

hs.eventtap.checkMouseButtons() -> {[key: string]: boolean}

Returns the currently pressed mouse buttons
hs.eventtap.checkMouseButtons() -> {[key: string]: boolean}
{[key: string]: boolean}
A dictionary with keys "left", "right", "middle" mapping to booleans
const buttons = hs.eventtap.checkMouseButtons()
if (buttons.left) console.log("Left button held")

hs.eventtap.mouseLocation() -> {[key: string]: number}

Returns the current mouse cursor position in Hammerspoon screen coordinates (top-left origin of primary display, y increases downward, matching hs.screen).
hs.eventtap.mouseLocation() -> {[key: string]: number}
{[key: string]: number}
A dictionary with "x" and "y" keys
const pos = hs.eventtap.mouseLocation()
console.log("Mouse at " + pos.x + ", " + pos.y)

hs.eventtap.doubleClickInterval() -> number

Returns the system double-click interval in seconds
hs.eventtap.doubleClickInterval() -> number
number
The maximum time between clicks that counts as a double-click
console.log("Double-click interval: " + hs.eventtap.doubleClickInterval())

hs.eventtap.keyRepeatDelay() -> number

Returns the system key repeat delay in seconds
hs.eventtap.keyRepeatDelay() -> number
number
The delay before key repeat begins
console.log("Key repeat delay: " + hs.eventtap.keyRepeatDelay())

hs.eventtap.keyRepeatInterval() -> number

Returns the system key repeat interval in seconds
hs.eventtap.keyRepeatInterval() -> number
number
The interval between repeated key events
console.log("Key repeat interval: " + hs.eventtap.keyRepeatInterval())