Compare commits

...

2 Commits

Author SHA1 Message Date
Noah b8665c8b8d TouchScreenMode Fix
Made some fixes to touchscreen control detection:

* TouchScreenMode is activated on the first SDL2 FingerDown
* TouchScreenMode deactivates after the last finger is removed, and a
  mouse event happens at least 5 ticks later.
2024-04-19 22:42:47 -07:00
Noah 5b3121171e Fix touchscreen mode detection
* Touchscreen mode used to be detected based on SDL2 GetNumTouchDevices
  but on a Macbook, the trackpad registers as a touch device - worse,
  GetNumTouchDevices will only start returning 1 the first time some
  devices are touched.
* The result was that on macOS the custom mouse cursor was drawn by
  default, but on the first trackpad touch, would disappear in favor of
  assuming the game is running on a touch screen device (which is not
  the case).
* New method: the render engine has an IsFingerDown boolean which will
  be true as long as at least one finger has registered a FingerDown
  event, but not yet a FingerUp event.
* So as long as one finger is down, the mouse cursor can disappear and
  then it comes back on release. This isn't perfectly ideal for pure
  touch devices (ideally the cursor remains hidden until a mouse
  movement without touch occurs).
2024-04-19 22:01:33 -07:00
9 changed files with 71 additions and 28 deletions

View File

@ -19,7 +19,6 @@ import (
"git.kirsle.net/SketchyMaze/doodle/pkg/chatbot"
"git.kirsle.net/SketchyMaze/doodle/pkg/gamepad"
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
"git.kirsle.net/SketchyMaze/doodle/pkg/native"
"git.kirsle.net/SketchyMaze/doodle/pkg/plus/bootstrap"
"git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp"
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
@ -215,9 +214,7 @@ func main() {
usercfg.Load()
// Hide the mouse cursor over the window, we draw our own sprite image for it.
if !native.HasTouchscreen(engine) {
engine.ShowCursor(false)
}
engine.ShowCursor(false)
// Set the app window icon.
if engine, ok := game.Engine.(*sdl.Renderer); ok {
@ -253,7 +250,7 @@ func main() {
// Log some basic environment details.
w, h := engine.WindowSize()
log.Info("Has touchscreen? %+v Window size: %dx%d", native.HasTouchscreen(engine), w, h)
log.Info("Window size: %dx%d", w, h)
game.Run()
return nil

View File

@ -25,7 +25,7 @@ var NoCursor = &Cursor{}
// Draw the cursor on screen. NOTE: Does not draw on touchscreen devices.
func Draw(e render.Engine) {
if native.HasTouchscreen(e) {
if native.IsTouchScreenMode() {
return
}

View File

@ -146,6 +146,9 @@ func (d *Doodle) Run() error {
d.width, d.height = d.Engine.WindowSize()
}
// Update touch screen control (mainly whether to show the mouse cursor).
native.UpdateTouchScreenMode(ev)
// Let the gamepad controller check for events, if it's in MouseMode
// it will fake the mouse cursor.
gamepad.Loop(ev)

View File

@ -19,14 +19,6 @@ import (
// Native render engine functions (SDL2 edition),
// not for JavaScript/WASM yet.
// HasTouchscreen checks if the device has at least one SDL_GetNumTouchDevices.
func HasTouchscreen(e render.Engine) bool {
if _, ok := e.(*sdl.Renderer); ok {
return sdl2.GetNumTouchDevices() > 0
}
return false
}
// CopyToClipboard puts some text on your clipboard.
func CopyToClipboard(text string) error {
if _, ok := shmem.CurrentRenderEngine.(*sdl.Renderer); ok {

View File

@ -10,10 +10,6 @@ import (
"git.kirsle.net/go/render"
)
func HasTouchscreen(e render.Engine) bool {
return false
}
func TextToImage(e render.Engine, text render.Text) (image.Image, error) {
return nil, errors.New("not supported on WASM")
}

View File

@ -0,0 +1,60 @@
package native
import (
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
"git.kirsle.net/go/render/event"
)
// Common code to handle basic touch screen detection.
var (
isTouchScreenMode bool
lastFingerDownTick uint64
)
// IsTouchScreenMode is activated when the user has touched the screen, and false when the mouse is moved.
func IsTouchScreenMode() bool {
return isTouchScreenMode
}
/*
UpdateTouchScreenMode evaluates whether the primary game input is a touch screen rather than a mouse cursor.
The game always hides the OS cursor (if it exists) and may draw its own custom mouse cursor.
On a touch screen device (such as a mobile), the custom mouse cursor should not be drawn, either, as
it would jump around to wherever the user last touched and be distracting.
TouchScreenMode is activated when a touch event has been triggered (at least one finger was down).
TouchScreenMode deactivates and shows the mouse cursor when no finger is held down, and then a mouse
event has occurred. So if the user has a touch screen laptop, wiggling the actual mouse input will
bring the cursor back.
*/
func UpdateTouchScreenMode(ev *event.State) {
// If a finger is presently down, record the current tick.
if ev.IsFingerDown {
lastFingerDownTick = shmem.Tick
}
if !isTouchScreenMode {
// We are NOT in touch screen mode. Touching the screen will change this.
if ev.IsFingerDown {
log.Info("TouchScreenMode ON")
isTouchScreenMode = true
}
} else {
// We ARE in touch screen mode. Wait for all fingers to be lifted.
if !ev.IsFingerDown {
// If we have registered a mouse event a few ticks after the finger was
// removed, it is a real mouse cursor and we exit touch screen mode.
if ev.IsMouseEvent && shmem.Tick-lastFingerDownTick > 5 {
log.Info("TouchScreenMode OFF")
isTouchScreenMode = false
}
}
}
}

View File

@ -5,6 +5,7 @@ import (
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
"git.kirsle.net/SketchyMaze/doodle/pkg/native"
"git.kirsle.net/SketchyMaze/doodle/pkg/usercfg"
"git.kirsle.net/go/render"
"git.kirsle.net/go/render/event"
@ -119,7 +120,9 @@ func (s *PlayScene) LoopTouchable(ev *event.State) {
// DrawTouchable draws any UI elements if needed for the touch UI.
func (s *PlayScene) DrawTouchable() {
if usercfg.Current.HideTouchHints {
// If we are not in touch mode (user has not touched their screen at all), don't
// show the hints - mouse & keyboard mode. And user opt-out setting.
if !native.IsTouchScreenMode() || usercfg.Current.HideTouchHints {
return
}

View File

@ -56,7 +56,7 @@ func (w *Canvas) loopEditorScroll(ev *event.State) error {
}
// Multitouch events to pan the level, like middle click on desktop.
if ev.Touching {
if ev.Touching && ev.TouchNumFingers > 1 {
// Intention: user drags with 2 fingers to scroll the canvas.
// SDL2 will register one finger also as a Button1 mouse click.
// We need to record the "mouse cursor" as start point but then

View File

@ -18,8 +18,6 @@ import (
"path/filepath"
"time"
"git.kirsle.net/SketchyMaze/doodle/pkg/native"
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
"git.kirsle.net/SketchyMaze/doodle/pkg/userdir"
"git.kirsle.net/go/render"
)
@ -57,12 +55,6 @@ var Current = Defaults()
// Defaults returns sensible default user settings.
func Defaults() *Settings {
settings := &Settings{}
// If not a touchscreen device, disable touchscreen hints as default.
if !native.HasTouchscreen(shmem.CurrentRenderEngine) {
settings.HideTouchHints = true
}
return settings
}