mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-02-25 17:30:09 +01:00
parent
a113687d56
commit
cb56906e14
67
examples/setcursorposition/main.go
Normal file
67
examples/setcursorposition/main.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2024 The Ebitengine Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
screenWidth = 640
|
||||||
|
screenHeight = 480
|
||||||
|
)
|
||||||
|
|
||||||
|
type Game struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Update() error {
|
||||||
|
x, y := ebiten.CursorPosition()
|
||||||
|
if ebiten.IsKeyPressed(ebiten.KeyLeft) || ebiten.IsKeyPressed(ebiten.KeyA) {
|
||||||
|
x--
|
||||||
|
}
|
||||||
|
if ebiten.IsKeyPressed(ebiten.KeyRight) || ebiten.IsKeyPressed(ebiten.KeyD) {
|
||||||
|
x++
|
||||||
|
}
|
||||||
|
if ebiten.IsKeyPressed(ebiten.KeyUp) || ebiten.IsKeyPressed(ebiten.KeyW) {
|
||||||
|
y--
|
||||||
|
}
|
||||||
|
if ebiten.IsKeyPressed(ebiten.KeyDown) || ebiten.IsKeyPressed(ebiten.KeyS) {
|
||||||
|
y++
|
||||||
|
}
|
||||||
|
ebiten.SetCursorPosition(x, y)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Draw(screen *ebiten.Image) {
|
||||||
|
x, y := ebiten.CursorPosition()
|
||||||
|
ebitenutil.DebugPrint(screen, fmt.Sprintf("Cursor Position: (%d, %d)\nPress arrow keys or WASD keys.", x, y))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||||
|
return screenWidth, screenHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ebiten.SetWindowSize(screenWidth, screenHeight)
|
||||||
|
ebiten.SetWindowTitle("SetCursorPosition (Ebitengine Demo)")
|
||||||
|
ebiten.SetCursorPosition(screenWidth/2, screenHeight/2)
|
||||||
|
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
20
input.go
20
input.go
@ -74,17 +74,27 @@ func KeyName(key Key) string {
|
|||||||
return ui.Get().KeyName(ui.Key(key))
|
return ui.Get().KeyName(ui.Key(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CursorPosition returns a position of a mouse cursor relative to the game screen (window). The cursor position is
|
// CursorPosition returns a position of a mouse cursor relative to the game screen (window).
|
||||||
// 'logical' position and this considers the scale of the screen.
|
// The cursor position is 'logical' position and this considers the scale of the screen.
|
||||||
//
|
//
|
||||||
// CursorPosition returns (0, 0) before the main loop on desktops and browsers.
|
// CursorPosition returns (0, 0) or the position set by SetCursorPosition before the main loop on desktops and browsers.
|
||||||
//
|
//
|
||||||
// CursorPosition always returns (0, 0) on mobile native applications.
|
// CursorPosition always returns (0, 0) on mobile native applications.
|
||||||
//
|
//
|
||||||
// CursorPosition is concurrent-safe.
|
// CursorPosition is concurrent-safe.
|
||||||
func CursorPosition() (x, y int) {
|
func CursorPosition() (x, y int) {
|
||||||
cx, cy := theInputState.cursorPosition()
|
// For the cursor position, theInputState is not used since the cursor position can be updated by SetCursorPosition.
|
||||||
return int(cx), int(cy)
|
return ui.Get().CursorPosition()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCursorPosition sets the cursor position.
|
||||||
|
// The cursor position is 'logical' position and this considers the scale of the screen.
|
||||||
|
//
|
||||||
|
// SetCursorPosition works only on desktops. SetCursorPosition does nothing otherwise.
|
||||||
|
//
|
||||||
|
// SetCursorPosition is concurrent-safe.
|
||||||
|
func SetCursorPosition(x, y int) {
|
||||||
|
ui.Get().SetCursorPosition(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wheel returns x and y offsets of the mouse wheel or touchpad scroll.
|
// Wheel returns x and y offsets of the mouse wheel or touchpad scroll.
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/file"
|
"github.com/hajimehoshi/ebiten/v2/internal/file"
|
||||||
@ -72,6 +73,8 @@ type userInterfaceImpl struct {
|
|||||||
initMonitor *Monitor
|
initMonitor *Monitor
|
||||||
initFullscreen bool
|
initFullscreen bool
|
||||||
initCursorMode CursorMode
|
initCursorMode CursorMode
|
||||||
|
initCursorX int
|
||||||
|
initCursorY int
|
||||||
initWindowDecorated bool
|
initWindowDecorated bool
|
||||||
initWindowPositionXInDIP int
|
initWindowPositionXInDIP int
|
||||||
initWindowPositionYInDIP int
|
initWindowPositionYInDIP int
|
||||||
@ -84,7 +87,7 @@ type userInterfaceImpl struct {
|
|||||||
initUnfocused bool
|
initUnfocused bool
|
||||||
|
|
||||||
// bufferOnceSwapped must be accessed from the main thread.
|
// bufferOnceSwapped must be accessed from the main thread.
|
||||||
bufferOnceSwapped bool
|
bufferOnceSwapped atomic.Bool
|
||||||
|
|
||||||
origWindowPosX int
|
origWindowPosX int
|
||||||
origWindowPosY int
|
origWindowPosY int
|
||||||
@ -133,6 +136,8 @@ func (u *UserInterface) init() error {
|
|||||||
maxWindowWidthInDIP: glfw.DontCare,
|
maxWindowWidthInDIP: glfw.DontCare,
|
||||||
maxWindowHeightInDIP: glfw.DontCare,
|
maxWindowHeightInDIP: glfw.DontCare,
|
||||||
initCursorMode: CursorModeVisible,
|
initCursorMode: CursorModeVisible,
|
||||||
|
initCursorX: invalidPos,
|
||||||
|
initCursorY: invalidPos,
|
||||||
initWindowDecorated: true,
|
initWindowDecorated: true,
|
||||||
initWindowPositionXInDIP: invalidPos,
|
initWindowPositionXInDIP: invalidPos,
|
||||||
initWindowPositionYInDIP: invalidPos,
|
initWindowPositionYInDIP: invalidPos,
|
||||||
@ -409,6 +414,19 @@ func (u *UserInterface) setInitCursorMode(mode CursorMode) {
|
|||||||
u.m.Unlock()
|
u.m.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) setInitCursorPosition(x, y int) {
|
||||||
|
u.m.Lock()
|
||||||
|
defer u.m.Unlock()
|
||||||
|
u.initCursorX = x
|
||||||
|
u.initCursorY = y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) getInitCursorPosition() (int, int) {
|
||||||
|
u.m.RLock()
|
||||||
|
defer u.m.RUnlock()
|
||||||
|
return u.initCursorX, u.initCursorY
|
||||||
|
}
|
||||||
|
|
||||||
func (u *UserInterface) getCursorShape() CursorShape {
|
func (u *UserInterface) getCursorShape() CursorShape {
|
||||||
u.m.RLock()
|
u.m.RLock()
|
||||||
v := u.cursorShape
|
v := u.cursorShape
|
||||||
@ -1292,14 +1310,22 @@ func (u *UserInterface) update() (float64, float64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// On macOS, one swapping buffers seems required before entering fullscreen (#2599).
|
// On macOS, one swapping buffers seems required before entering fullscreen (#2599).
|
||||||
if u.isInitFullscreen() && (u.bufferOnceSwapped || runtime.GOOS != "darwin") {
|
if u.isInitFullscreen() && (u.bufferOnceSwapped.Load() || runtime.GOOS != "darwin") {
|
||||||
if err := u.setFullscreen(true); err != nil {
|
if err := u.setFullscreen(true); err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
u.setInitFullscreen(false)
|
u.setInitFullscreen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "darwin" && u.bufferOnceSwapped {
|
if !u.bufferOnceSwapped.Load() {
|
||||||
|
if x, y := u.getInitCursorPosition(); x != invalidPos && y != invalidPos {
|
||||||
|
if err := u.setCursorPosition(x, y); err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS == "darwin" && u.bufferOnceSwapped.Load() {
|
||||||
var err error
|
var err error
|
||||||
u.darwinInitOnce.Do(func() {
|
u.darwinInitOnce.Do(func() {
|
||||||
// On macOS, window decoration should be initialized once after buffers are swapped (#2600).
|
// On macOS, window decoration should be initialized once after buffers are swapped (#2600).
|
||||||
@ -1316,7 +1342,7 @@ func (u *UserInterface) update() (float64, float64, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.bufferOnceSwapped {
|
if u.bufferOnceSwapped.Load() {
|
||||||
var err error
|
var err error
|
||||||
u.showWindowOnce.Do(func() {
|
u.showWindowOnce.Do(func() {
|
||||||
// Show the window after first buffer swap to avoid flash of white especially on Windows.
|
// Show the window after first buffer swap to avoid flash of white especially on Windows.
|
||||||
@ -1390,7 +1416,7 @@ func (u *UserInterface) update() (float64, float64, error) {
|
|||||||
|
|
||||||
// If isRunnableOnUnfocused is false and the window is not focused, wait here.
|
// If isRunnableOnUnfocused is false and the window is not focused, wait here.
|
||||||
// For the first update, skip this check as the window might not be seen yet in some environments like ChromeOS (#3091).
|
// For the first update, skip this check as the window might not be seen yet in some environments like ChromeOS (#3091).
|
||||||
for !u.isRunnableOnUnfocused() && u.bufferOnceSwapped {
|
for !u.isRunnableOnUnfocused() && u.bufferOnceSwapped.Load() {
|
||||||
// In the initial state on macOS, the window is not shown (#2620).
|
// In the initial state on macOS, the window is not shown (#2620).
|
||||||
visible, err := u.window.GetAttrib(glfw.Visible)
|
visible, err := u.window.GetAttrib(glfw.Visible)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1493,9 +1519,7 @@ func (u *UserInterface) updateGame() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u.bufferOnceSwappedOnce.Do(func() {
|
u.bufferOnceSwappedOnce.Do(func() {
|
||||||
u.mainThread.Call(func() {
|
u.bufferOnceSwapped.Store(true)
|
||||||
u.bufferOnceSwapped = true
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if unfocused {
|
if unfocused {
|
||||||
@ -2178,3 +2202,51 @@ func (u *UserInterface) RunOnMainThread(f func()) {
|
|||||||
func dipToNativePixels(x float64, scale float64) float64 {
|
func dipToNativePixels(x float64, scale float64) float64 {
|
||||||
return dipToGLFWPixel(x, scale)
|
return dipToGLFWPixel(x, scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) CursorPosition() (x, y int) {
|
||||||
|
if !u.isRunning() || !u.bufferOnceSwapped.Load() {
|
||||||
|
x, y := u.getInitCursorPosition()
|
||||||
|
if x == invalidPos || y == invalidPos {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
return x, y
|
||||||
|
}
|
||||||
|
|
||||||
|
u.m.Lock()
|
||||||
|
defer u.m.Unlock()
|
||||||
|
return int(u.inputState.CursorX), int(u.inputState.CursorY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) SetCursorPosition(x, y int) {
|
||||||
|
if !u.isRunning() {
|
||||||
|
u.setInitCursorPosition(x, y)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u.mainThread.Call(func() {
|
||||||
|
if err := u.setCursorPosition(x, y); err != nil {
|
||||||
|
u.setError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// setCursorPosition must be called from the main thread.
|
||||||
|
func (u *UserInterface) setCursorPosition(x, y int) error {
|
||||||
|
m, err := u.currentMonitor()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := m.DeviceScaleFactor()
|
||||||
|
cx, cy := u.context.logicalPositionToClientPosition(float64(x), float64(y), s)
|
||||||
|
gx := dipToGLFWPixel(cx, s)
|
||||||
|
gy := dipToGLFWPixel(cy, s)
|
||||||
|
u.window.SetCursorPos(gx, gy)
|
||||||
|
|
||||||
|
u.m.Lock()
|
||||||
|
defer u.m.Unlock()
|
||||||
|
u.inputState.CursorX = float64(x)
|
||||||
|
u.inputState.CursorY = float64(y)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -864,3 +864,13 @@ func IsScreenTransparentAvailable() bool {
|
|||||||
func dipToNativePixels(x float64, scale float64) float64 {
|
func dipToNativePixels(x float64, scale float64) float64 {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) CursorPosition() (x, y int) {
|
||||||
|
u.m.Lock()
|
||||||
|
defer u.m.Unlock()
|
||||||
|
return int(u.inputState.CursorX), int(u.inputState.CursorY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) SetCursorPosition(x, y int) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
@ -337,3 +337,13 @@ func (u *UserInterface) UsesStrictContextRestoration() bool {
|
|||||||
func IsScreenTransparentAvailable() bool {
|
func IsScreenTransparentAvailable() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) CursorPosition() (x, y int) {
|
||||||
|
u.m.Lock()
|
||||||
|
defer u.m.Unlock()
|
||||||
|
return int(u.inputState.CursorX), int(u.inputState.CursorY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) SetCursorPosition(x, y int) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
@ -187,3 +187,13 @@ func IsScreenTransparentAvailable() bool {
|
|||||||
func dipToNativePixels(x float64, scale float64) float64 {
|
func dipToNativePixels(x float64, scale float64) float64 {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) CursorPosition() (x, y int) {
|
||||||
|
u.m.Lock()
|
||||||
|
defer u.m.Unlock()
|
||||||
|
return int(u.inputState.CursorX), int(u.inputState.CursorY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) SetCursorPosition(x, y int) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
@ -180,3 +180,13 @@ func IsScreenTransparentAvailable() bool {
|
|||||||
func dipToNativePixels(x float64, scale float64) float64 {
|
func dipToNativePixels(x float64, scale float64) float64 {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) CursorPosition() (x, y int) {
|
||||||
|
u.m.Lock()
|
||||||
|
defer u.m.Unlock()
|
||||||
|
return int(u.inputState.CursorX), int(u.inputState.CursorY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) SetCursorPosition(x, y int) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user