
Swift package that provides precise information about the position and bounds of the text cursor (caret) in macOS applications. It leverages the macOS Accessibility API to retrieve the caret's location and bounding rectangle, with fallbacks
Compatible with macOS 12.0 and later
CursorBounds primarily finds the cursor caret, the blinking line or block that indicates where the next character will appear when typing. If the caret's position cannot be retrieved, it falls back to the bounding rectangle of the focused text area or field. When neither the caret nor the bounding rectangle is accessible, it uses the position of the mouse cursor as a final fallback.
- Retrieve the position of the text caret (cursor) in macOS apps.
- Get the bounding rectangle of the caret for text fields and text areas.
- Graceful handling of unsupported or restricted applications.
- Built-in fallback mechanisms for robust behavior.
- Error logging and levels (see below, or check documentation)
To include CursorBounds
in your project:
- Open your Xcode project.
- Go to File > Add Packages....
- Paste the following URL in the search bar:
https://github.com/aeastr/CursorBounds.git
- Choose the desired version and click Add Package.
To retrieve the current origin, call the getOrigin
method:
let origin = CursorBounds().getOrigin()
The getOrigin method accepts the following parameters:
- correctionMode (default: .adjustForYAxis):
- Determines whether to apply a Y-axis correction to account for screen coordinate differences between CGPoint and NSPoint.
- Options:
- .none: No correction is applied.
- .adjustForYAxis: Adjusts the Y-coordinate to align with the screen’s coordinate system.
- xCorner (default: .minX):
- Specifies which X-coordinate of the bounding box to use.
- Options:
- .minX: Use the minimum X-coordinate.
- .maxX: Use the maximum X-coordinate.
- yCorner (default: .minY):
- Specifies which Y-coordinate of the bounding box to use.
- Options:
- .minY: Use the minimum Y-coordinate.
- .maxY: Use the maximum Y-coordinate.
if let origin = CursorBounds().getOrigin() {
print("Origin ID: \(origin.id)")
print("Origin Type: \(origin.type.rawValue)")
print("Origin Coordinates: x = \(origin.NSPoint.x), y = \(origin.NSPoint.y)")
} else {
print("Failed to retrieve origin.")
}
if let origin = CursorBounds().getOrigin(correctionMode: .none) {
print("Origin Coordinates without Y-axis correction: x = \(origin.NSPoint.x), y = \(origin.NSPoint.y)")
}
if let origin = CursorBounds().getOrigin(xCorner: .maxX, yCorner: .maxY) {
print("Top-right corner coordinates: x = \(origin.NSPoint.x), y = \(origin.NSPoint.y)")
}
if let origin = CursorBounds().getOrigin(correctionMode: .none, xCorner: .maxX, yCorner: .minY) {
print("Ucorrected bottom-right corner coordinates: x = \(origin.NSPoint.x), y = \(origin.NSPoint.y)")
}
The getOrigin
method returns an optional Origin
object (Origin?
). If successful, you’ll receive an Origin
with the following structure:
public struct Origin: Hashable {
public private(set) var id: UUID
public var type: OriginType
public var NSPoint: NSPoint
public init(id: UUID = UUID(), type: OriginType, NSPoint: NSPoint) {
self.id = id
self.type = type
self.NSPoint = NSPoint
}
}
NSPoint in Origin
represents the calculated location of the top left point of the rect
The type
property of Origin
indicates the source of the origin. It is an enum with the following cases:
public enum OriginType: String {
case caret = "Caret" // Represents a caret position
case rect = "Text Rect" // Represents a text field/area bounding rect
case mouseCursor = "Mouse Cursor" // Represents the mouse cursor position
}
You can control the verbosity of the logs by setting the logLevel
in CursorBoundsConfig
. View log documentation For example, to enable debug-level logging:
CursorBoundsConfig.shared.logLevel = .debug
The available log levels include:
.debug
: For detailed information useful during development..info
: For general informational logs..warning
: For recoverable issues..error
: For critical errors..none
: No logs at all.
CursorPlayground is included in this package, you can quickly test out the main function of CursorBounds here
- macOS 12.0+
- Swift 5.5+
- Accessibility permissions must be granted to the app.
- App Sanbox must be disabled
To use this package, your app must have Accessibility permissions, and App Sanbox must be disabled. Accessibility permissions can be configured in System Preferences > Privacy & Security > Accessibility. Ensure that your app is checked in the list of allowed apps.
This project is licensed under the MIT License.
Contributions are welcome! Please fork this repository and submit a pull request for review.
- Built with the macOS Accessibility API for seamless integration.
- Inspired by the need for better tools to enhance text navigation and accessibility in macOS apps.