From b186bc1e9406e7bd407867c285212a6b8f6e45a6 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 12 Aug 2017 15:39:41 +0900 Subject: [PATCH] ui: Add IsCursorVisible (#377) --- examples/windowsize/main.go | 13 ++++++-- internal/ui/ui_glfw.go | 63 ++++++++++++++++++++++++++++++------- internal/ui/ui_js.go | 5 +++ internal/ui/ui_mobile.go | 4 +++ run.go | 16 ++++++++-- 5 files changed, 85 insertions(+), 16 deletions(-) diff --git a/examples/windowsize/main.go b/examples/windowsize/main.go index ff8821414..d1c80a792 100644 --- a/examples/windowsize/main.go +++ b/examples/windowsize/main.go @@ -43,6 +43,7 @@ var ( ebiten.KeyS: 0, ebiten.KeyF: 0, ebiten.KeyB: 0, + ebiten.KeyC: 0, } count = 0 ) @@ -60,6 +61,7 @@ func update(screen *ebiten.Image) error { screenWidth, screenHeight := screen.Size() fullscreen := ebiten.IsFullscreen() runnableInBackground := ebiten.IsRunnableInBackground() + cursorVisible := ebiten.IsCursorVisible() if keyStates[ebiten.KeyUp] == 1 { screenHeight += d @@ -86,7 +88,7 @@ func update(screen *ebiten.Image) error { case 2: screenScale = 1 default: - panic("not reach") + panic("not reached") } } if keyStates[ebiten.KeyF] == 1 { @@ -95,10 +97,14 @@ func update(screen *ebiten.Image) error { if keyStates[ebiten.KeyB] == 1 { runnableInBackground = !runnableInBackground } + if keyStates[ebiten.KeyC] == 1 { + cursorVisible = !cursorVisible + } ebiten.SetScreenSize(screenWidth, screenHeight) ebiten.SetScreenScale(screenScale) ebiten.SetFullscreen(fullscreen) ebiten.SetRunnableInBackground(runnableInBackground) + ebiten.SetCursorVisibility(cursorVisible) count++ @@ -119,8 +125,9 @@ func update(screen *ebiten.Image) error { x, y := ebiten.CursorPosition() msg := fmt.Sprintf(`Press arrow keys to change the window size Press S key to change the window scale -Press F key to change the fullscreen state -Press B key to change the run-in-background state +Press F key to switch the fullscreen state +Press B key to switch the run-in-background state +Press C key to switch the cursor visibility Cursor: (%d, %d) FPS: %0.2f`, x, y, ebiten.CurrentFPS()) ebitenutil.DebugPrint(screen, msg) diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index 7ed6d19ae..2b3abe5b3 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -45,6 +45,7 @@ type userInterface struct { origPosX int origPosY int initFullscreen bool + initCursorVisible bool runnableInBackground bool m sync.Mutex } @@ -81,6 +82,13 @@ func initialize() error { currentUI.funcs = make(chan func()) currentUI.window.MakeContextCurrent() + + mode := glfw.CursorNormal + if !currentUI.isInitCursorVisible() { + mode = glfw.CursorHidden + } + currentUI.window.SetInputMode(glfw.CursorMode, mode) + return nil } @@ -134,6 +142,19 @@ func (u *userInterface) setInitFullscreen(initFullscreen bool) { u.m.Unlock() } +func (u *userInterface) isInitCursorVisible() bool { + u.m.Lock() + v := u.initCursorVisible + u.m.Unlock() + return v +} + +func (u *userInterface) setInitCursorVisible(visible bool) { + u.m.Lock() + u.initCursorVisible = visible + u.m.Unlock() +} + func (u *userInterface) isRunnableInBackground() bool { u.m.Lock() v := u.runnableInBackground @@ -269,18 +290,33 @@ func adjustCursorPosition(x, y int) (int, int) { return x - int(ox/s), y - int(oy/s) } +func IsCursorVisible() bool { + u := currentUI + if !u.isRunning() { + return u.isInitCursorVisible() + } + v := false + _ = currentUI.runOnMainThread(func() error { + v = currentUI.window.GetInputMode(glfw.CursorMode) == glfw.CursorNormal + return nil + }) + return v +} + func SetCursorVisibility(visible bool) { - // This can be called before Run: change the state asyncly. - go func() { - _ = currentUI.runOnMainThread(func() error { - c := glfw.CursorNormal - if !visible { - c = glfw.CursorHidden - } - currentUI.window.SetInputMode(glfw.CursorMode, c) - return nil - }) - }() + u := currentUI + if !u.isRunning() { + u.setInitCursorVisible(visible) + return + } + _ = currentUI.runOnMainThread(func() error { + c := glfw.CursorNormal + if !visible { + c = glfw.CursorHidden + } + currentUI.window.SetInputMode(glfw.CursorMode, c) + return nil + }) } func Run(width, height int, scale float64, title string, g GraphicsContext) error { @@ -502,7 +538,12 @@ func (u *userInterface) setScreenSize(width, height int, scale float64, fullscre // SwapInterval is affected by the current monitor of the window. // This needs to be called at least after SetMonitor. // Without SwapInterval after SetMonitor, vsynch doesn't work (#375). + // + // TODO: (#405) If triple buffering is needed, SwapInterval(0) should be called, + // but is this correct? If glfw.SwapInterval(0) and the driver doesn't support triple + // buffering, what will happen? glfw.SwapInterval(1) + // TODO: Rename this variable? u.sizeChanged = true return true diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index e76a8d549..08a76065a 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -84,6 +84,11 @@ func adjustCursorPosition(x, y int) (int, int) { return x, y } +func IsCursorVisible() bool { + // The initial value is an empty string, so don't compare with "auto" here. + return canvas.Get("style").Get("cursor").String() != "none" +} + func SetCursorVisibility(visibility bool) { if visibility { canvas.Get("style").Set("cursor", "auto") diff --git a/internal/ui/ui_mobile.go b/internal/ui/ui_mobile.go index a943f04dd..793fdfb68 100644 --- a/internal/ui/ui_mobile.go +++ b/internal/ui/ui_mobile.go @@ -114,6 +114,10 @@ func adjustCursorPosition(x, y int) (int, int) { return x, y } +func IsCursorVisible() bool { + return false +} + func SetCursorVisibility(visibility bool) { // Do nothing } diff --git a/run.go b/run.go index 4afd1a962..e9626b200 100644 --- a/run.go +++ b/run.go @@ -179,8 +179,20 @@ func ScreenScale() float64 { return ui.ScreenScale() } +// IsCursorVisible returns a boolean value indicating whether +// the cursor is visible or not. +// +// IsCursorVisible always returns false on mobiles. +// +// This function is concurrent-safe. +func IsCursorVisible() bool { + return ui.IsCursorVisible() +} + // SetCursorVisibility changes the state of cursor visiblity. // +// SetCursorVisibility does nothing on mobiles. +// // This function is concurrent-safe. func SetCursorVisibility(visible bool) { ui.SetCursorVisibility(visible) @@ -205,7 +217,7 @@ func IsFullscreen() bool { // On browsers, the game screen is resized to fit with the body element (client) size. // Additionally, the game screen is automatically resized when the body element is resized. // -// SetFullscreen doesn't work on mobiles. +// SetFullscreen does nothing on mobiles. // // This function is concurrent-safe. func SetFullscreen(fullscreen bool) { @@ -227,7 +239,7 @@ func IsRunnableInBackground() bool { // Known issue: On browsers, even if the state is on, the game doesn't run in background tabs. // This is because browsers throttles background tabs not to often update. // -// SetRunnableInBackground doesn't work on mobiles so far. +// SetRunnableInBackground does nothing on mobiles so far. // // This function is concurrent-safe. func SetRunnableInBackground(runnableInBackground bool) {