[PATCH] Sync host mouse position to Atari one when line-A base is known |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/hatari-devel Archives
]
- Subject: [PATCH] Sync host mouse position to Atari one when line-A base is known
- From: Eero Tamminen <oak@xxxxxxxxxxxxxx>
- Date: Fri, 8 Nov 2019 23:51:58 +0200
Do this when resolution is changed (instead of warping host mouse to
middle of screen) and when Hatari window gets keyboard focus. Mouse
position sync is based on TOS line-A mouse co-ordinates at negative
offsets from line-A base.
Warping is done only when Hatari window has keyboard focus, because
warp may move mouse out of Hatari window, if it's partially covered by
some other window. With focus-follows-mouse windowing policy, Hatari
gets keyboard focus also on mouse enter, so that isn't really
compatible with mouse warping. With click-to-focus windowing policy
(Windows etc) it should work fine though.
Above fixes also an issue where mouse is warped on screen resolution
changes (which can be frequent in Falcon demos), *although* Hatari
window isn't focused or visible at all.
To help debugging issues with window management events, this adds also
DEBUG log level output for them.
I've tested this to work with TOS versions 1.04 - TOS 4.04 and EmuTOS.
Note that line-A mouse co-ordinate variables are available only when
cartridge code has registered line-A variable addresses. I.e. one
needs to enable GEMDOS HD or VDI mode (or tracing for osbase, gemdos,
vdi or aes) for full host mouse sync.
---
doc/hatari.1 | 10 +++++--
src/includes/vdi.h | 1 +
src/main.c | 70 ++++++++++++++++++++++++++++++++++++++++------
src/screen.c | 11 ++++++--
src/vdi.c | 20 ++++++++++++-
5 files changed, 98 insertions(+), 14 deletions(-)
diff --git a/doc/hatari.1 b/doc/hatari.1
index 99138ad8..7a926c35 100644
--- a/doc/hatari.1
+++ b/doc/hatari.1
@@ -113,8 +113,14 @@ Skip <x> frames after each displayed frame to accelerate emulation
Slow down emulation by factor of x (used as multiplier for VBL wait time)
.TP
.B \-\-mousewarp <bool>
-To keep host mouse better in sync with Atari mouse pointer, center it
-to Hatari window on cold reset and resolution changes
+To sync host mouse position with Atari mouse pointer, when Hatari
+window is focused, its size changes or there's an emulation reset (at
+which point TOS centers mouse to screen). Note that this is not
+recommended with (Linux desktop) focus-follows-mouse windowing policy,
+or with programs (demos) overwriting TOS line-A variables, and that
+full host mouse sync is enabled only when GEMDOS HD or VDI mode is
+also enabled (cartridge code for those fetches the required TOS line-A
+base address)!
.TP
.B \-\-statusbar <bool>
Show statusbar (with floppy leds etc etc)
diff --git a/src/includes/vdi.h b/src/includes/vdi.h
index 78afd1ba..cabd8d1a 100644
--- a/src/includes/vdi.h
+++ b/src/includes/vdi.h
@@ -51,6 +51,7 @@ extern void AES_Info(FILE *fp, Uint32 bShowOpcodes);
extern void VDI_Info(FILE *fp, Uint32 bShowOpcodes);
extern bool VDI_AES_Entry(void);
extern void VDI_LineA(Uint32 LineABase, Uint32 FontBase);
+extern bool VDI_GetMousePos(int *x, int *y);
extern void VDI_Complete(void);
extern void VDI_Reset(void);
diff --git a/src/main.c b/src/main.c
index e1a6f191..60709a29 100644
--- a/src/main.c
+++ b/src/main.c
@@ -52,6 +52,7 @@ const char Main_fileid[] = "Hatari main.c : " __DATE__ " " __TIME__;
#include "stMemory.h"
#include "str.h"
#include "tos.h"
+#include "vdi.h"
#include "video.h"
#include "avi_record.h"
#include "debugui.h"
@@ -80,7 +81,9 @@ static int nVBLSlowdown = 1; /* host VBL wait multiplier */
static bool bEmulationActive = true; /* Run emulation when started */
static bool bAccurateDelays; /* Host system has an accurate SDL_Delay()? */
+
static bool bIgnoreNextMouseMotion = false; /* Next mouse motion will be ignored (needed after SDL_WarpMouse) */
+static bool bWinInFocus; /* whether window has keyboard focus */
/*-----------------------------------------------------------------------*/
/**
@@ -435,12 +438,22 @@ static void Main_CheckForAccurateDelays(void)
* Set mouse pointer to new x,y coordinates and set flag to ignore
* the mouse event that is generated by SDL_WarpMouse().
*
- * Skip the request is it's not position restore and mouse warping is disabled.
+ * Skip the request if:
+ * - it's not position restore and mouse warping is disabled,
+ * - window doesn't have keyboard focus (user isn't interacting with it), or
+ * - warping is to outside of screen.
*/
void Main_WarpMouse(int x, int y, bool restore)
{
if (!(restore || ConfigureParams.Screen.bMouseWarp))
return;
+ if (!bWinInFocus)
+ return;
+ if (x < 0 || x >= sdlscrn->w || y < 0 || y >= sdlscrn->h)
+ {
+ Log_Printf(LOG_WARN, "Mouse warp requested outside of Hatari window\n");
+ return;
+ }
#if WITH_SDL2
SDL_WarpMouseInWindow(sdlWindow, x, y);
#else
@@ -501,10 +514,11 @@ static void Main_HandleMouseMotion(SDL_Event *pEvent)
*/
void Main_EventHandler(void)
{
- bool bContinueProcessing;
+ bool bContinueProcessing, bOldInFocus;
SDL_Event event;
int events;
int remotepause;
+ const char *evname;
do
{
@@ -635,15 +649,53 @@ void Main_EventHandler(void)
break;
case SDL_WINDOWEVENT:
- if (event.window.event == SDL_WINDOWEVENT_EXPOSED
- && !ConfigureParams.Screen.bUseSdlRenderer)
+ bOldInFocus = bWinInFocus;
+
+ switch(event.window.event) {
+ case SDL_WINDOWEVENT_EXPOSED:
+ evname = "EXPOSED";
+ if (!ConfigureParams.Screen.bUseSdlRenderer)
+ {
+ /* Hack: Redraw screen here when going into
+ * fullscreen mode without SDL renderer */
+ sdlscrn = SDL_GetWindowSurface(sdlWindow);
+ Screen_SetFullUpdate();
+ Statusbar_Init(sdlscrn);
+ }
+ break;
+ /* keyboard focus */
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ evname = "FOCUS_GAINED";
+ bWinInFocus = true;
+ break;
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ evname = "FOCUS_LOST";
+ bWinInFocus = false;
+ break;
+ /* rest of window events */
+ case SDL_WINDOWEVENT_SIZE_CHANGED: evname = "SIZE_CHANGED"; break;
+ case SDL_WINDOWEVENT_TAKE_FOCUS:evname = "TAKE_FOCUS"; break;
+ case SDL_WINDOWEVENT_ENTER: evname = "ENTER"; break;
+ case SDL_WINDOWEVENT_LEAVE: evname = "LEAVE"; break;
+ case SDL_WINDOWEVENT_MOVED: evname = "MOVED"; break;
+ case SDL_WINDOWEVENT_RESIZED: evname = "RESIZED"; break;
+ case SDL_WINDOWEVENT_RESTORED: evname = "RESTORED"; break;
+ case SDL_WINDOWEVENT_MAXIMIZED: evname = "MAXIMIZED"; break;
+ case SDL_WINDOWEVENT_MINIMIZED: evname = "MINIMIZED"; break;
+ case SDL_WINDOWEVENT_SHOWN: evname = "SHOWN"; break;
+ case SDL_WINDOWEVENT_HIDDEN: evname = "HIDDEN"; break;
+ case SDL_WINDOWEVENT_CLOSE: evname = "CLOSE"; break;
+ default: evname = "Unknown";
+ }
+ Log_Printf(LOG_DEBUG, "Window event: %s\n", evname);
+
+ if (bWinInFocus && bWinInFocus != bOldInFocus)
{
- /* Hack: Redraw screen here when going into
- * fullscreen mode without SDL renderer */
- sdlscrn = SDL_GetWindowSurface(sdlWindow);
- Screen_SetFullUpdate();
- Statusbar_Init(sdlscrn);
+ int x, y;
+ if (VDI_GetMousePos(&x, &y))
+ Main_WarpMouse(x * nScreenZoomX, y * nScreenZoomX, false);
}
+
/* Note: any changes here should most likely be done
* also in sdlgui.c::SDLGui_DoDialog()
*/
diff --git a/src/screen.c b/src/screen.c
index 16249883..41902c87 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1371,7 +1371,7 @@ void Screen_SetGenConvSize(int width, int height, int bpp, bool bForceChange)
{
const bool keep = ConfigureParams.Screen.bKeepResolution;
int screenwidth, screenheight, maxw, maxh;
- int scalex, scaley, sbarheight;
+ int scalex, scaley, sbarheight, x, y;
if (bpp == 24)
bpp = 32;
@@ -1501,7 +1501,14 @@ void Screen_SetGenConvSize(int width, int height, int bpp, bool bForceChange)
sdlscrn->format->Rshift, sdlscrn->format->Gshift, sdlscrn->format->Bshift,
sdlscrn->format->Rloss, sdlscrn->format->Gloss, sdlscrn->format->Bloss));
- Main_WarpMouse(sdlscrn->w/2,sdlscrn->h/2, false);
+ if (VDI_GetMousePos(&x, &y)) {
+ x *= nScreenZoomX;
+ y *= nScreenZoomX;
+ } else {
+ x = sdlscrn->w/2;
+ y = sdlscrn->h/2;
+ }
+ Main_WarpMouse(x, y, false);
}
void Screen_GenConvUpdate(SDL_Rect *extra, bool forced)
diff --git a/src/vdi.c b/src/vdi.c
index d51232ca..35e5fbf9 100644
--- a/src/vdi.c
+++ b/src/vdi.c
@@ -62,12 +62,14 @@ static Uint16 AESOpCode;
/*-----------------------------------------------------------------------*/
/**
- * Called to reset VDI variables on reset.
+ * Called to reset VDI & LineA variables on reset.
*/
void VDI_Reset(void)
{
/* no VDI calls in progress */
VDI_OldPC = 0;
+ /* LineA base address is still unknown */
+ LineABase = 0;
}
/*-----------------------------------------------------------------------*/
@@ -825,6 +827,22 @@ void VDI_LineA(Uint32 linea, Uint32 fontbase)
}
}
+/*-----------------------------------------------------------------------*/
+/**
+ * Get mouse x, y position from LineA variables if LineABase is known,
+ * to be used for mouse position synchronization with host.
+ *
+ * Return true for success, false for failure
+ */
+bool VDI_GetMousePos(int *x, int *y)
+{
+ if (!LineABase) {
+ return false;
+ }
+ *x = STMemory_ReadWord(LineABase - 602); /* GCURX */
+ *y = STMemory_ReadWord(LineABase - 600); /* GCURY */
+ return true;
+}
/*-----------------------------------------------------------------------*/
/**
--
2.20.1
--------------996AB3E343AB2BD2121F94F8--