Skip to content

feat: Added HoverCursorStyle to APIs using OSC 22#676

Merged
kommander merged 17 commits intoanomalyco:mainfrom
viralcodex:hover-cursor-style
Feb 16, 2026
Merged

feat: Added HoverCursorStyle to APIs using OSC 22#676
kommander merged 17 commits intoanomalyco:mainfrom
viralcodex:hover-cursor-style

Conversation

@viralcodex
Copy link
Copy Markdown
Contributor

Fixes: #611

Hi @kommander,

Added Custom cursor styles for the openTUI API through MouseCursorStyle.
Includes: pointer, disabled, crosshair, and move.

Used OSC 22 and demo-ed on kitty terminal.

I have added all of them for usage (and future usage) but I can remove them if needed.

Child elements can override the parent hoverCursorStyle.

Also on shutdown the states reset to default cursors (added shutdown code in both native and typescript code)

opentui2.mp4

Let me know if changes are needed, will do accordingly.

Thanks :)

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Feb 12, 2026

@opentui/core

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core@b6c8237

@opentui/react

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/react@b6c8237

@opentui/solid

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/solid@b6c8237

@opentui/core-darwin-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-darwin-arm64@b6c8237

@opentui/core-darwin-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-darwin-x64@b6c8237

@opentui/core-linux-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-linux-arm64@b6c8237

@opentui/core-linux-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-linux-x64@b6c8237

@opentui/core-win32-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-win32-arm64@b6c8237

@opentui/core-win32-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-win32-x64@b6c8237

commit: b6c8237

Copy link
Copy Markdown
Collaborator

@kommander kommander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can keep this lower level for the lib and let solid/react or the app level take care of how and when to apply the cursor style.

moveCursor: (row: number, col: number) => `\x1b[${row};${col}H`,
moveCursorAndClear: (row: number, col: number) => `\x1b[${row};${col}H\x1b[J`,

setMousePointer: (shape: string) => `\x1b]22;${shape}\x07`,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be on the zig side, passing the option down.

Copy link
Copy Markdown
Contributor Author

@viralcodex viralcodex Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok moving the whole setting the mouse pointer to zig side

maybeRenderable.processMouseEvent(event)
}

this.updateMousePointerOnHover(maybeRenderable)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not every Renderable is potentially hoverable, but I see where that is coming from. I thought that maybe that could be something that an app controls itself? It would be like:

r.onMouseOver = (evt) => evt.target.ctx.setCursorStyle(...)

}
}

public setMousePointer(shape: MousePointerStyle): void {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a method setCursorStyle already, which takes options that could be adjusted. It's currently this:

 public static setCursorStyle(
    renderer: CliRenderer,
    style: CursorStyle,
    blinking: boolean = false,
    color?: RGBA,
  ): void {

It's messy, so we could make that proper like:

public static setCursorStyle(
    renderer: CliRenderer,
    options: CursorStyleOptions
  ): void {

Where the CursorStyleOptions become:

export interface cursorstyleoptions {
  style: "block" | "line" | "underline"
  blinking: boolean,
  color: RGBA,
  cursor: "default" | "pointer" | "text" | "crosshair" | "move" | "not-allowed"
}

Then it can be properly packed as FFI Struct in zig-structs.ts and passed down to zig, which can hold the cursor state and update the changed values.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are two setCursorStyles here in the class, one is static one that you mentioned and one instance method, should I update that with this as well?

Then I will have to change the signature at a lot of places

@viralcodex
Copy link
Copy Markdown
Contributor Author

Hi @kommander,
Made some changes, unified the whole styles thing as far as I could understand to CursorStyleOptions using a single struct to zig.

Also, since mouse pointer and Cursor styles were mandatory in the object/struct, I had to pass defaults everytime I was making an update to one of them, so made all props optional, and update as the app required.

Also made change to let the app decide instead of passing a prop to the elements.

I could be missing something or may have written something in a wrong way, so please let me know and I'll fix it.

@viralcodex
Copy link
Copy Markdown
Contributor Author

here's verifying both cursor and mouse pointer:

opentui.mp4

this._destroyFinalized = true
this._destroyPending = false

this.resetMousePointer()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should happen in Terminal.zig, in the shutdown sequence I think.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must have missed it from 1st commit, will do it.

@kommander
Copy link
Copy Markdown
Collaborator

Looks way better 👍 thanks! You think we could update the docs here as well, like the website docs? cc @simonklee maybe you can glimpse over it as well, I think it looks good and can be iterated on.

@viralcodex
Copy link
Copy Markdown
Contributor Author

@kommander thanks, yes we can, should I add the web docs change here as well, or should I raise a separate PR after merging this one? Whatever works for you guys :)

@viralcodex viralcodex requested a review from kommander February 13, 2026 19:49
@kommander
Copy link
Copy Markdown
Collaborator

When @simonklee is fine we can merge this and document in another PR

@viralcodex
Copy link
Copy Markdown
Contributor Author

Thanks, will raise another PR and link it here for the documentation

@kommander kommander merged commit c81d755 into anomalyco:main Feb 16, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: custom cursor styles

3 participants