joncampbell123 / dosbox-x

DOSBox-X fork of the DOSBox project
GNU General Public License v2.0
2.81k stars 383 forks source link

Mouse coordinates broken in fullscreen mode (desktop resolution of 1920x1080) #993

Open lwchkg opened 5 years ago

lwchkg commented 5 years ago

Describe the bug The mouse cursor is bounded to only a part of the screen (either upper part or left part), depending on the exact game played. Movement of mouse cursor is out of aspect ratio.

The games affected appears to be using SVGA only (I don't have enough data to confirm this, but I failed to reproduce on games with CGA and MCGA resolution). Initial analysis suggests that dosbox-x using wrong resolutions in the mouse code.

To Reproduce Steps to reproduce the behavior:

  1. Start DosBox-X in fullscreen mode. (Resolution = desktop on 1920x1080 screen) Switching to fullscreen from windows mode is okay.)
  2. Start the game.
  3. Move the mouse.

Expected behavior The mouse pointer moves around the whole screen.

Actual behavior See the description of the bug.

Screenshots and Analysis m2v140_000 Note: MOO2. The mouse pointer is already moved to the far right position, but pointer is shown in the middle of the screen. (Appears that x = 369, but I don't understand why this happens.)

destroy_001 Note: Destroy Man. The mouse pointer is already moved to the far bottom, but appears only on y=199. Appears that the mouse code is using a wrong resolution of 640x200.

Environment (please complete the following information):

dosbox-x dfend wrapper.zip. Put this next to dosbox-x.exe if needed.

DOSBOX.CONF generated by D-Fend (MOO2)

joncampbell123 commented 5 years ago

Is this a problem if you capture the mouse cursor?

dnlopez commented 5 years ago

I have something that sounds similar to this. Desktop resolution of 1920x1080, Arch Linux, with an SDL 1 build.

I'm starting up a Windows 3.1 desktop in Dosbox for most of my tests though I see the same thing happening in DOS games too like Frontier and Loom.

In windowed mode, when I capture the mouse (either with Ctrl-F10, or the middle mouse button, or if autolock=true then the left mouse button), the host pointer disappears and I can move the guest pointer fully within the guest screen with no problems. When I uncapture the mouse again (either with Ctrl-F10, or the middle mouse button), the host pointer reappears in the exact place it was when originally captured. (So I suppose that from the host's point of view, its pointer was 'locked' all that time and the emulator is using relative mouse measurements).

In fullscreen mode, when I capture the mouse, I can move the guest pointer around to some extent but soon find it restricted to some rectangle smaller than the guest screen. If I then move to eg. the top-left corner of that limited rectangle and uncapture the mouse, the host pointer reappears in the top-left corner of the screen. If I then move the host pointer to the bottom-right of the host screen and recapture the mouse, I can now move the guest pointer within a limited rectangle of the same size as before but which is positioned exactly one diagonal step up and to the left of where the limited rectangle was previously. (So it appears that the host pointer, though invisible, is not locked in place during this time and when it hits the screen edge the emulator is not seeing attempted mouse movements beyond that).

You're more likely to see this if the mouse sensitivity is low, because then the rectangle that the guest pointer gets trapped in ends up being smaller. Also, I find that it's easier to observe all this when autolock=true, as then the host pointer is visible while uncaptured and in fullscreen, whereas when autolock=false the pointer isn't visible in this situation, though I'm fairly sure it otherwise exhibits the same behaviour.

Since my Dosbox is self-compiled, I tried adding this to the top of HandleMouseMotion(SDL_MouseMotionEvent * motion) in sdlmain.cpp: printf("xrel: %d, yrel: %d\n", motion->xrel, motion->yrel);

With that, in windowed mode, I can capture the mouse and then move it downwards as far as I like for a neverending stream of "yrel: 127". In fullscreen mode, after some initial travel I ultimately get repeated "yrel: 0". So the values entering in with the SDL_MOUSEMOTION event are part of the problem.

That's as far as I delved. I've just tried an SDL 2 build and the problem has gone away.

heftig commented 5 years ago

Reverting c4ee6e5fd3d282c1ad6774e01b966a7bad70aae3 restores proper mouse integration with MoO2.

It seems that MoO2 reads the mouse before setting the mouse ranges it wants (0-1278 on X, 0-479 on Y, for mode 0x69).

joncampbell123 commented 5 years ago

I see.

Some games and programs define the range on initial mode set while others use the INT 33h defaults. Guest/host pointer integration with INT 33h is required in order for them to match up.

Some programs will use very large values (DeluxePaint II) like 0-5627 and 0-4958 in the VGA modes.

heftig commented 5 years ago

What did c4ee6e5 fix?

joncampbell123 commented 5 years ago

I don't recall the game it fixed, but this feature needs options to disable/enable or set the range.

Ideally the 640x200 or 640x400 screen coordinate range offered by INT 31h would be universal but it seems some games like to re-define the range which breaks mouse pointer integration. Most do it after init or modeset, which is fine, but some handle INT 31h in a different order.

I know of one game that starts up with the mouse bounded to a window instead of fullscreen which confuses this code.