hs.eventtap
ModuleMonitor 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.
Declaration
hs.eventtap.addWatcher(types, callback, listenOnly) -> HSEventTap
Parameters
| 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). |
Returns
HSEventTap
An HSEventTap watcher, or null if the tap could not be created
Notes
event tap watchers will not be automatically destroyed by JavaScript garbage collection. You *MUST* call `removeWatcher()` if you want to dispose of a watcher.
Example
// 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
Declaration
hs.eventtap.removeWatcher(tap) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| tap | HSEventTap | The HSEventTap returned by `addWatcher` |
Returns
None
Example
hs.eventtap.removeWatcher(tap)
hs.eventtap.makeKeyEvent(key, isDown) -> HSEventTapEvent
Create a keyboard event
Declaration
hs.eventtap.makeKeyEvent(key, isDown) -> HSEventTapEvent
Parameters
| 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 |
Returns
HSEventTapEvent
An HSEventTapEvent, or null if the key name is unknown
Example
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
Declaration
hs.eventtap.makeKeyEventWithCode(keyCode, isDown) -> HSEventTapEvent
Parameters
| Name | Type | Description |
|---|---|---|
| keyCode | number | A numeric virtual key code |
| isDown | boolean | true for key down, false for key up |
Returns
HSEventTapEvent
An HSEventTapEvent
Example
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`.
Declaration
hs.eventtap.makeMouseEvent(type, x, y, button) -> HSEventTapEvent
Parameters
| 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) |
Returns
HSEventTapEvent
An HSEventTapEvent, or null if the event could not be created
Example
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).
Declaration
hs.eventtap.makeScrollWheelEvent(deltaX, deltaY, x, y) -> HSEventTapEvent
Parameters
| 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 |
Returns
HSEventTapEvent
An HSEventTapEvent, or null if the event could not be created
Example
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.
Declaration
hs.eventtap.keyStroke(mods, key) -> None
Parameters
| 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") |
Returns
None
Example
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.
Declaration
hs.eventtap.keyStrokes(text) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| text | string | The string to type |
Returns
None
Example
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).
Declaration
hs.eventtap.leftClick(x, y) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| x | number | Horizontal position in Hammerspoon screen coordinates |
| y | number | Vertical position in Hammerspoon screen coordinates |
Returns
None
Example
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).
Declaration
hs.eventtap.rightClick(x, y) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| x | number | Horizontal position in Hammerspoon screen coordinates |
| y | number | Vertical position in Hammerspoon screen coordinates |
Returns
None
Example
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).
Declaration
hs.eventtap.doubleLeftClick(x, y) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| x | number | Horizontal position in Hammerspoon screen coordinates |
| y | number | Vertical position in Hammerspoon screen coordinates |
Returns
None
Example
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).
Declaration
hs.eventtap.middleClick(x, y) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| x | number | Horizontal position in Hammerspoon screen coordinates |
| y | number | Vertical position in Hammerspoon screen coordinates |
Returns
None
Example
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).
Declaration
hs.eventtap.scrollWheel(deltaX, deltaY, x, y) -> None
Parameters
| 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 |
Returns
None
Example
hs.eventtap.scrollWheel(0, 3, 500, 400) // Scroll down 3 lines
hs.eventtap.currentModifiers() -> string[]
Returns the currently held modifier keys
Declaration
hs.eventtap.currentModifiers() -> string[]
Returns
string[]
An array of modifier key names such as ["cmd", "shift"]
Example
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
Declaration
hs.eventtap.checkMouseButtons() -> {[key: string]: boolean}
Returns
{[key: string]: boolean}
A dictionary with keys "left", "right", "middle" mapping to booleans
Example
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).
Declaration
hs.eventtap.mouseLocation() -> {[key: string]: number}
Returns
{[key: string]: number}
A dictionary with "x" and "y" keys
Example
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
Declaration
hs.eventtap.doubleClickInterval() -> number
Returns
number
The maximum time between clicks that counts as a double-click
Example
console.log("Double-click interval: " + hs.eventtap.doubleClickInterval())
hs.eventtap.keyRepeatDelay() -> number
Returns the system key repeat delay in seconds
Declaration
hs.eventtap.keyRepeatDelay() -> number
Returns
number
The delay before key repeat begins
Example
console.log("Key repeat delay: " + hs.eventtap.keyRepeatDelay())
hs.eventtap.keyRepeatInterval() -> number
Returns the system key repeat interval in seconds
Declaration
hs.eventtap.keyRepeatInterval() -> number
Returns
number
The interval between repeated key events
Example
console.log("Key repeat interval: " + hs.eventtap.keyRepeatInterval())