From b8665c8b8deb6ba9cfb5d9a64b06ac200e5e430b Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Fri, 19 Apr 2024 22:42:47 -0700 Subject: [PATCH] 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. --- cmd/doodle/main.go | 3 +- pkg/cursor/cursor.go | 2 +- pkg/doodle.go | 17 ++--------- pkg/native/engine_sdl.go | 11 ------- pkg/native/engine_wasm.go | 4 --- pkg/native/touch_screen.go | 60 ++++++++++++++++++++++++++++++++++---- pkg/play_scene_touch.go | 5 +++- pkg/usercfg/usercfg.go | 8 ----- 8 files changed, 63 insertions(+), 47 deletions(-) diff --git a/cmd/doodle/main.go b/cmd/doodle/main.go index 0f54587..5434ad2 100644 --- a/cmd/doodle/main.go +++ b/cmd/doodle/main.go @@ -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" @@ -251,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 diff --git a/pkg/cursor/cursor.go b/pkg/cursor/cursor.go index 629812b..f7f3253 100644 --- a/pkg/cursor/cursor.go +++ b/pkg/cursor/cursor.go @@ -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.IsTouchScreenMode { + if native.IsTouchScreenMode() { return } diff --git a/pkg/doodle.go b/pkg/doodle.go index 80c28e0..dd30904 100644 --- a/pkg/doodle.go +++ b/pkg/doodle.go @@ -141,25 +141,14 @@ func (d *Doodle) Run() error { } d.event = ev - // If they have touched a touch screen, set the touchscreen mode boolean. This - // will hide the mouse cursor until they let up off the screen. - if !native.IsTouchScreenMode { - if ev.IsFingerDown { - log.Debug("TouchScreenMode ON!") - native.IsTouchScreenMode = true - } - } else { - if !ev.IsFingerDown { - log.Debug("TouchScreenMode OFF") - native.IsTouchScreenMode = false - } - } - // Always have an accurate idea of the window size. if ev.WindowResized { 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) diff --git a/pkg/native/engine_sdl.go b/pkg/native/engine_sdl.go index 57b6cb0..c3726f6 100644 --- a/pkg/native/engine_sdl.go +++ b/pkg/native/engine_sdl.go @@ -19,17 +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. -// -// Note: SDL2 GetNumTouchDevices will sometimes return 0 until a touch device is actually touched. On Macbooks, -// the trackpad counts as a touch device and on first touch, HasTouchscreen may begin returning true. -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 { diff --git a/pkg/native/engine_wasm.go b/pkg/native/engine_wasm.go index 2a5099e..09b4544 100644 --- a/pkg/native/engine_wasm.go +++ b/pkg/native/engine_wasm.go @@ -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") } diff --git a/pkg/native/touch_screen.go b/pkg/native/touch_screen.go index ce5c136..6b0f899 100644 --- a/pkg/native/touch_screen.go +++ b/pkg/native/touch_screen.go @@ -1,12 +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. -/* -IsTouchScreenMode is set to true when the user has touched the screen, and false when the mouse is moved. +var ( + isTouchScreenMode bool + lastFingerDownTick uint64 +) -This informs the game's control scheme: if the user has a touch screen and they've touched it, -the custom mouse cursor is hidden (as it becomes distracting) and if they then move a real mouse -over the window, the custom cursor appears again and we assume non-touchscreen mode once more. +// 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. */ -var IsTouchScreenMode bool +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 + } + } + } +} diff --git a/pkg/play_scene_touch.go b/pkg/play_scene_touch.go index 8b435c0..87a55f5 100644 --- a/pkg/play_scene_touch.go +++ b/pkg/play_scene_touch.go @@ -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 } diff --git a/pkg/usercfg/usercfg.go b/pkg/usercfg/usercfg.go index 55cf56a..eece31b 100644 --- a/pkg/usercfg/usercfg.go +++ b/pkg/usercfg/usercfg.go @@ -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 }