ebiten: Add more CursorShapeTypes

Created on 15 Apr 2021  路  19Comments  路  Source: hajimehoshi/ebiten

For example, Ebiten doesn't add cursors GLFW_HRESIZE_CURSOR and GLFW_VRESIZE_CURSOR since they seem different on macOS from other platforms. Actually they seem like col-resize and row-resize in CSS on macOS instead of ew-resize and ns-resize shapes in CSS (See the NSCursor API document). To show ew-resize and nw-resize on macOS, we'd need to use undocumented APIs unfortunately. Then, instead of relying on GLFW APIs, we'd need to use native APIs directly.

If we could use native APIs directly, we could add more various system cursors.

feature

All 19 comments

I'd like to tackle this issue. Could you assign it?

This is what I have so far...

static void setNativeCursor(int cursorID) {
  id cursor = [[NSCursor class] performSelector:@selector(arrowCursor)];
  switch(cursorID){
    case 0:
      cursor = [[NSCursor class] performSelector:@selector(_horizontalResizeCursor)];
      break;
    case 1:
      cursor = [[NSCursor class] performSelector:@selector(_verticalResizeCursor)];
      break;
  }
  [cursor push];
}
func (u *UserInterface) setNativeCursor(cursor driver.CursorShape) {
    switch cursor {
    case driver.CursorShapeHorizontalResize:
        C.setNativeCursor(C.int(0))
    case driver.CursorShapeVerticalResize:
        C.setNativeCursor(C.int(1))
    }
}

Extended to support existing cursors.

Awesome! Please go ahead.

Unsure as how to approach Windows. https://docs.microsoft.com/en-us/windows/win32/menurc/using-cursors
Need access to the winapi message loop 馃

How does GLFW do to change the cursor shape?

Hmm
I'll test later if it's possible to call anywhere

void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{
    if (cursorInContentArea(window))
        updateCursorImage(window);
}
static void updateCursorImage(_GLFWwindow* window)
{
    if (window->cursorMode == GLFW_CURSOR_NORMAL)
    {
        if (window->cursor)
            SetCursor(window->cursor->win32.handle);
        else
            SetCursor(LoadCursorW(NULL, IDC_ARROW));
    }
    else
        SetCursor(NULL);
}

Currently tearing apart the chain of functions from ebiten to glfw that set the cursor

Yes. Actually Ebiten loads system cursors at the initialization phase.

Any idea where that location is?

Ah yes. So I guess for MacOS we only need the native implementation. Windows and Unix should already support horizontal and vertical resize.

For horizontal and vertical resize shapes, yes. For other shapes that GLFW doesn't have, we'd have to implement by ourselves.

Should I make stubs for setNativeCursor in ui_unix.go and ui_windows.go?

Then I just do this

func (u *UserInterface) SetCursorShape(shape driver.CursorShape) {
    old := u.setCursorShape(shape)
    if old == shape {
        return
    }
    if !u.isRunning() {
        return
    }
    if runtime.GOOS == "darwin" {
        _ = u.t.Call(func() error {
            u.setNativeCursor(shape)
            return nil
        })
    } else {
        _ = u.t.Call(func() error {
            u.window.SetCursor(glfwSystemCursors[shape])
            return nil
        })
    }
}

Should I make stubs for setNativeCursor in ui_unix.go and ui_windows.go?

Yes, just empty functions should be fine.

EDIT: what does setNativeCursor do?

It calls an objc function that sets the cursors

func (u *UserInterface) setNativeCursor(cursor driver.CursorShape) {
    switch cursor {
    case driver.CursorShapeHorizontalResize:
        C.setNativeCursor(C.int(0))
    case driver.CursorShapeVerticalResize:
        C.setNativeCursor(C.int(1))
    case driver.CursorShapeDefault:
        C.setNativeCursor(C.int(2))
    case driver.CursorShapePointer:
        C.setNativeCursor(C.int(3))
    case driver.CursorShapeText:
        C.setNativeCursor(C.int(4))
    }
}

=>
```objc
static void setNativeCursor(int cursorID) {
id cursor = [[NSCursor class] performSelector:@selector(arrowCursor)];
switch(cursorID){
case 0:
cursor = [[NSCursor class] performSelector:@selector(_windowResizeEastWestCursor)];
break;
case 1:
cursor = [[NSCursor class] performSelector:@selector(_windowResizeNorthSouthCursor)];
break;
case 2:
cursor = [[NSCursor class] performSelector:@selector(arrowCursor)];
break;
case 3:
cursor = [[NSCursor class] performSelector:@selector(openHandCursor)];
break;
case 4:
cursor = [[NSCursor class] performSelector:@selector(IBeamCursor)];
break;
}
[cursor push];
}

Thanks. Let's have setNativeCursor with u.window.SetCursor for Windows and Linux/UNIX, and leave TODO comment to use the native APIs in the future.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hajimehoshi picture hajimehoshi  路  5Comments

hajimehoshi picture hajimehoshi  路  4Comments

mortenson picture mortenson  路  7Comments

silbinarywolf picture silbinarywolf  路  4Comments

joaowiciuk picture joaowiciuk  路  5Comments