Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows 3.1 absolute mouse #1552

Closed
stuaxo opened this issue Nov 27, 2021 · 77 comments
Closed

Windows 3.1 absolute mouse #1552

stuaxo opened this issue Nov 27, 2021 · 77 comments

Comments

@stuaxo
Copy link
Contributor

stuaxo commented Nov 27, 2021

https://github.com/NattyNarwhal/vmwmouse

There is a new mouse driver for Windows 3.1 in VMware, it could provide a basis for more seamless mouse support in dosemu2 in Windows 3.1.

Apologies if this isn't needed, I'm not in front of a computer to test right now.

@stuaxo
Copy link
Contributor Author

stuaxo commented Nov 27, 2021

Reading the doc linked from there about the VMware back door
https://wiki.osdev.org/VMware_tools#Absolute_Mouse_Coordinates

The API seems to have some things that are useful.
I realise dosemu has its own mechanism via its special interrupt, but it's interesting that according to the doc Qemu implements some of the functionality.

I guess this is as close to a sort of standard it's possible to get in host/guest communication.

@stsp
Copy link
Member

stsp commented Nov 27, 2021

So we can add a new mouse
back-end to dosemu2 for better
mouse support under vmware
and qemu. May be good for
fdpp-buildroot project, but
fdpp-buildroot project is not
yet showing its value, other than
to debug KVM problems.

Or we can add similar mechanism
for guest-side mouse tracking,
but to only support this win3.1
mouse driver, whereas we already
have our own which is not any
worse.

Not sure which of the above 2
possibilities do you have in mind.
Both tasks are quite simple and
practically almost useless, but
the patches are welcome. Why
not to support something new.

@stuaxo
Copy link
Contributor Author

stuaxo commented Nov 27, 2021

Thanks for more fully thinking this through.

One practical thing I will do is some tests to verify our driver works as this does in the gif in their README, when it comes to moving the mouse in and out of the DOSEMU2 Window, I seem to recall various instances where it's not as well synced, but that could be due to my environment not DOSEMU2 itself.

@stsp
Copy link
Member

stsp commented Nov 27, 2021

@stsp
Copy link
Member

stsp commented Nov 27, 2021

OK, there seem to be no qemu
support for that mouse option.
It seems to be specific to vmware.
qemu seems to only support
USB tablet for this, but under
fdpp-buildroot that usb-tablet
sucks (mouse becomes way
too sensitive to be usable).
I wonder if it is the qemu bug
or something else.

stsp added a commit to dosemu2/fdpp-buildroot that referenced this issue Nov 27, 2021
Should work under vmmware (not tested).
See dosemu2/dosemu2#1552
@stsp
Copy link
Member

stsp commented Nov 27, 2021

Should now be fixed.
I added vmware and qemu mouses
support to fdpp-buildroot, and
submitted the patch to sdl with
qemu mouse/tablet support.
This is probably the best we
can aim for.
Given that this vmware mouse
is not supported by qemu, I see
zero need doing anything else.

@stuaxo
Copy link
Contributor Author

stuaxo commented Nov 27, 2021

Wow you added this before I managed to reply :)

I always thought tablet mode would = absolute mouse, but maybe not ?

I probably need to setup some Windows 3.1 VMs and see how the mouse works in them, which may result in a feature request to Qemu, but if tablet mode works could be moot.

Cheers for implementing this I'll do some testing.

@stuaxo
Copy link
Contributor Author

stuaxo commented Nov 27, 2021

I just found this:
NattyNarwhal/vmwmouse#1

Passing -device vmmouse when calling qemu-system-i386 should be enough to enable this implementation.

Will give it a go in a bit.

@stsp
Copy link
Member

stsp commented Nov 27, 2021

Doesn't work for me.

@NattyNarwhal
Copy link

Author of the original repo here, I'm going to try this in QEMU soon. Ping me if you have any questions about my source/the interface. I've been reading the QEMU impl source too.

@stsp
Copy link
Member

stsp commented Nov 28, 2021

Yes, there is such impl.
But at least the following
should happen to consider
that working:

  1. qemu should stop grabbing
    mouse on the click
  2. linux should detect the
    mechanism and start reporting
    absolute positions.

You can easily see both of the
above if you use -usbdevice tablet.
qemu stops grabbing mouse as
soon as the guest's tablet driver
initialized. With -device vmmouse
the grab is still happening, and
also I don't see in linux dmesg
that it detected vmmouse - it
seems to be still using relative
ps2 movements.
So maybe you can get that to
work properly, but tablet already
works (needs my sdl patch though).

@stsp
Copy link
Member

stsp commented Nov 28, 2021

The interface is also quite
strange:

Backdoor proc near
	
		mov eax, VMWARE_MAGIC
		mov dx, VMWARE_PORT
		in eax, dx
		ret
	
	Backdoor endp

Instead of having magic numbers
on port reads (never seen that before),
they (vmware) could just add the
new ps/2 commands for this.
Enter abs mode, leave abs mode,
get abs data, get abs resolution,
set abs resolution and all that.

In what resolution do they return
abs coords? Is it always similar
to guest screen resolution?

@stsp
Copy link
Member

stsp commented Nov 28, 2021

Already found an answer:
EBX = x (0 - FFFFh scaled).

@stsp
Copy link
Member

stsp commented Nov 28, 2021

So when you do in eax, dx
they seem to alter all registers,
not just eax.
OK, I basically understand that
horrible interface now. :)

@stsp
Copy link
Member

stsp commented Nov 28, 2021

Well, dosemu2 is simply not
prepared for that kind of hacks.
All it does, is: rAL = port_inb(a);.
And if inside port_inb() we are
going to update all other registers,
then we need to decide which ones:

  • real-mode
  • prot mode
  • the ones from CPU simulator
  • the ones in JITted code

dosemu2 keeps all the above
cases separately. There is no
simple way to update all registers
when the asm command is not
asking for that.

@stsp
Copy link
Member

stsp commented Nov 28, 2021

Likewise, port handler doesn't
have any context for reaching
the "magic value". All context
that the port handler has or
should have, is the port number
to read and/or the value to write.
Getting into CPU context is
especially difficult under JITted
code. It is only available after
JIT exits. Of course the exits
are controlled by an ioperm
bitmask, and the one can make
them unconditional... And then
only look for rm or pm CPU
contexts...
But let's just say Hell No to
the ugly hacks. :)

@NattyNarwhal
Copy link

Yes, the backdoor does clobber EAX-EDX. I do notice the PS/2 stream is altered when you switch to absolute mode; I don't know if the protocol changes and it can communicate position that way or if the stream is inert and only used as an interrupt source; either way, it seems what you're supposed to do is check for PS/2 mouse events, then disregard their contents and do hypercalls instead (once to query, if successful, again to read). If you actually read a PS/2 packet (assuming it's in the normal format), it just looks like it's drifting to the bottom right, forever.

I suspect a cleaner interface can probably be done; probably as you say, extending the PS/2 interface. Obviously, that'd need driver work again.

@stsp
Copy link
Member

stsp commented Nov 28, 2021

If you actually read a PS/2 packet (assuming it's in the normal format), it just looks like it's drifting to the bottom right, forever.

Maybe this is a trick to re-sync
the coords? We did that before
the abs coords appeared: you
drift to bottom-left for quite long,
and then, when you think the
cursor is in the corner, you move
down-right by the absolute coords.
Prog takes them as relative, but
from 0:0 it doesn't matter.

I suspect a cleaner interface can probably be done; probably as you say, extending the PS/2 interface.
Obviously, that'd need driver work again.

I suppose unless you work
for vmware, its not possible
to implement a cleaner interface. :)
As first it have to be supported
by vmware...

@NattyNarwhal
Copy link

NattyNarwhal commented Nov 28, 2021

Maybe this is a trick to re-sync the coords?

I've tried moving them for a while and it doesn't seem to be changing. (PS/2 button state does seem to work fine, so it makes me believe it's not being too misinterpreted.)

I suppose unless you work for vmware, its not possible to implement a cleaner interface. :) As first it have to be supported by vmware...

I don't, but it's quite possible DOSEmu doesn't have to repeat their mistakes. 🙃

Another note is that int 33h can actually deal with absolute coordinates, but in another way. I suspect you could possibly implement a mouse.com that deals in whatever absolute protocol and then teach the Windows mouse driver that 33h is (edit) absolute.

@stsp
Copy link
Member

stsp commented Nov 28, 2021

But we already have that. :)
You can find our int33 win31 driver by
the link in that thread.

@stsp
Copy link
Member

stsp commented Nov 29, 2021

implement a mouse.com

The way it is currently done,
requires no mouse.com because
dosemu is para-virtualizer, so
it just provides int33 on its own.
But to use our win31 int33 driver
under qemu, indeed some patched
mouse.com would be needed.
But I won't advertice the vmware's
protocol to ctmouse authors
because of that register clobbering
thing, and I won't advertise the
usb tablet to them as it is quite
difficult to support under DOS...
So I suspect there currently is
no good option for mouse.com
(aka ctmouse.exe).

@jschwartzenberg
Copy link
Member

There is a new mouse driver for Windows 3.1 in VMware, it could provide a basis for more seamless mouse support in dosemu2 in Windows 3.1.

I'm curious what it could provide beyond the current i33mouse driver? Does it have scroll wheel support like what I demo here? https://schwart6.home.xs4all.nl/win31-scrollwheel.ogv
I don't think there are any other things that could be improved.

@NattyNarwhal
Copy link

Funny you mention that, because I'm implementing this in the VMware mouse driver now 😬

@stsp
Copy link
Member

stsp commented Nov 29, 2021

How do we support wheel?
I can't find that neither in a
(very small) changelog, nor
in the code...
Magic.

@stsp
Copy link
Member

stsp commented Nov 29, 2021

Are you sure your demo shows
our i33mouse driver and not
something else?

@NattyNarwhal
Copy link

I can't speak for Julius' demo, but I've got my own implementation of this in a branch I haven't pushed yet, because it's kinda gross right now. What I basically do right now is:

  • At least with the VMware interface, use the wheel data returned in EDX (8-bit signed int, -1, 0, or 1)
  • Get the focused window (which is not ideal, because the focused window may not be the thing you want to scroll, and the thing you want to scroll may not be a focusable window. for another demo, I did a HWND_BROADCAST to top-level windows or GetActiveWindow, but those only work for again, top-level popups. I think I need to use GetCursorPos to get the position, then WindowFromPoint to get what's under the cursor, which incidentally would allow for )
  • If not 0, do a PostMessage (safe to call from an interrupt according to Raymond), sending a WM_VSCROLL to it (either SB_LINEUP or SB_LINEDOWN).

@stsp
Copy link
Member

stsp commented Nov 29, 2021

Would it be possible to make
this a separate driver or a dll,
and just provide another event_proc,
that our driver could call too,
as well as yours?

@NattyNarwhal
Copy link

Yes, it would have to be GetProcAddress'd, but I have to do that for USER anyways, because IIRC most drivers can only link against KERNEL.

@javispedro
Copy link

Another idea is to amplify sensitivity (fn 0x1a) after enlarging a window?

I like that, will try.

@javispedro
Copy link

Anyway, this is what I mean that SC2k is already jumpy even with unpatched dosemu:

sc2k_dosemu.mp4

Notice the vertical desync.

I don't have this problem at all with my int33 driver in VBox:

sc2k_vbmouse.mp4

Where I am not using the speed to scale the absolute coordinates -- just the window size.
(Need to try with SerfCity).

@stsp
Copy link
Member

stsp commented Apr 18, 2022

We have emumouse tool.
Try emumouse y 8 before starting sc2000.

@stsp
Copy link
Member

stsp commented Apr 18, 2022

Btw, sc2000 seems to do exactly
that: enlarges virtual window and
amplifies speed.
I do recommend to use sensitivity
instead of speed, but its the same
trick as you can do. :)

@javispedro
Copy link

javispedro commented Apr 18, 2022

Argh, I have been doing sensitivity incorrectly in my driver. int33.lst says that sensitivity is the same as speed, but even cutemouse itself treats sensitivity differently!

But yeah, I see SimCity does set speed to [1,1] which given screen coords 640x480 means scaled to 5120x"1920", at the same time it sets a window size 5120x3840 , so this explains the emumouse 8 y trick, the game is likely wrong. But to me it just shows we should use window size only for scaling , not speed.

Also dosemu uses 100 as the default sensitivity, but cutemouse uses 50 as default (and 100 is the max), and DOSBox copied the formula from cutemouse. What a mess =)

@stsp
Copy link
Member

stsp commented Apr 18, 2022

No problem to sync sensitivity with
other sources, as its rarely used. So
if it helps you, lets do that.
I am not sure why do you propose to
completely ignore speed.

@javispedro
Copy link

Okey I see the point. serfcity/settlers is just setting a window of "5000x5000" , not changing the mouse speed at all, then proceeds to compute its own deltas of the mouse cursor position instead of using mickeys (wtf) . As a consequence of the windowsize-based scaling the mouse moves too fast in DOSBox, while in dosemu is it usable (but I still get a lot of desyncs!).

There's another problem with speed/sensitivity: the coordinate system also scales with the screen resolution. Real hw int33 drivers don't know about SVGA and so they will still assume 640x200-based coordinates, but dosemu int33 knows about SVGA and so it will give you 800x600-based coordinates.
So again I cannot do a universal thing.

Sorry. I guess I'll just do the int66, then use int33/0x26 to see if int66 worked, otherwise do the 0x7FFF window thing for the rest.

@stsp
Copy link
Member

stsp commented Apr 18, 2022

but I still get a lot of desyncs!

But desyncs are unavoidable,
I do not even count them in.

but dosemu int33 knows about SVGA and so it will give you 800x600-based coordinates.

Try emumouse s 1 to disable VESA modes.
I think they were needed for PC-GEOS.

So again I cannot do a universal thing.

But you can query the resolution with
0x26, so why is it a problem that dosemu2
knows about VESA modes? You can
query the resolution, so why to assume
any particular resolution instead?

@javispedro
Copy link

javispedro commented Apr 18, 2022

I can query the resolution even with the Windows API, but the problem is that no other int33 driver will do the same.

My intention was to set speed to [1,1] and then a window to [5120,7680].
If the screen res is 640x480, this works everywhere.
Dosemu scales coordinates to 640 * 8 x 480 * 16 = 5120x7680
Dosbox, my driver, etc. scales coordinates using the window size = 5120x7680 again.

However on 800x600.
Dosemu now scales coordinates to 800 * 8 x 600 * 16 = 6400x9600
The rest still use the window size = 5120x7680

int33/26 result does not change to reflect this (in any of the drivers). Also dosemu returns bx=1 incorrectly on int33/26 (which means error / driver disabled according to int33.lst and cutemouse src), should be 0 to indicate driver enabled.

@stsp
Copy link
Member

stsp commented Apr 18, 2022

But you can query the resolution
via 0x26 to calculate the proper
speed values from that.
Don't set speed to 1:1, calculate
it from 2 resolutions.

@javispedro
Copy link

javispedro commented Apr 18, 2022

This logic works in all big 4 (Dosbox(-X), dosemu, Cutemouse, MS mouse):

// Set the speed to 1,1 to enlarge dosemu coordinate range by 8x16.
// In other absolute drivers, this doesn't change coordinates nor actual speed (which is inherited from host)
// In normal relative drivers, we'll use the raw mickeys anyways, so speed should also have no effect.
int33_set_mouse_speed(1, 1);

// Get what the int33 driver thinks the current coordinate range is
max_x = 0; max_y = 0;
int33_get_max_coordinates(&max_x, &max_y);
if (!max_x || !max_y) { max_x = 640; max_y = 200; } // For really bad drivers

// Multiply that by 8x16 to match dosemu coordinate range
// (and also in case the driver-provided coordinate range is too small)
max_x *= 8;
max_y *= 16;

// And use that to define the window size which is what most
// absolute drivers will use to define the coordinate range
int33_set_horizontal_window(0, max_x);
int33_set_vertical_window(0, max_y);

I couldn't use:

  • Sensitivity, since for some reason it affected the number of mickeys as given by Cutemouse (so it makes relative mouse either too slow or too fast). So I'm limited to changing speed (speed a.k.a. mickeysPerSecond doesn't change the number of mickeys reported by DOS drivers).
  • int66, since for some reason it crashes real hardware. Yes I checked to see if the interrupt vector was defined, and surprisingly it is (no idea why, but it pointed to something in windows).

@javispedro
Copy link

Pushed. Here's a bin if someone wants to try.

vbmousedrv.zip

@stsp
Copy link
Member

stsp commented Apr 18, 2022

Good algo!
But the driver is not yet.
When I start win31, if the host mouse
is initially inside the dosemu window,
then the very first mouse move makes
the windows cursor jump to the up-left
corner, resulting in a permanent desync.
Moving mouse outside of dosemu
window and back, fixes it until the
win31 restart.

@stsp
Copy link
Member

stsp commented Apr 18, 2022

Fixed it myself. :)

@stsp
Copy link
Member

stsp commented Apr 18, 2022

@Baron-von-Riedesel @jschwartzenberg
would you like to test this driver?
It looks pretty cool.
Wheel works!

@stsp
Copy link
Member

stsp commented Apr 19, 2022

I think https://depot.javispedro.com/vbox/vbados/
still doesn't have the latest version.
@javispedro Please ping when you
update the version, so we can update
the docs and remove our own driver
which seems no longer relevant.

Thank you!

@javispedro
Copy link

I have updated them to the last versions. But there are no new changes to win16 mouse since the binary from #1552 (comment)
The only changes are for the DOS driver which is not required here.

We also need to see if the win16 driver is not too crashy . Not sure that all these win16 API functions are reentrant/safe to call from int33 handler. If they aren't, I'll have to move the scroll wheel logic into a usermode .DLL .

@NattyNarwhal
Copy link

NattyNarwhal commented Apr 20, 2022

My guess is the functions we're calling seem mostly interrupt safe, because they don't do much:

  • GetCursorPos probably reads globals only
  • Reading window longs like class, style, parent, etc. should be safe
  • EnumChildWindows might have some recordkeeping on the stack, but it's, again, only reading values
  • WindowFromPoint has to look probably at USER state thoroughly, but again, reading

The only problem ones I could think of might be PostMessage (has to write messages somewhere).

Also note a few of the DDK drivers do call USER functions. (Some is also just display drivers trying to dig for GDI functions, or stuff with pluggable components like KEYBOARD.) Some even outright call MessageBox and PostMessage, which I think would be pretty complex. (Printer drivers also do it, but they seem universally written in C and are loaded pretty late in the game, so I think they're a special case of not being a special case.)

@stsp
Copy link
Member

stsp commented Apr 21, 2022

Just out of curiosity:
have you tried shutting down
windows native cursor and
enabling the int33 (host) cursor
instead?
Would be interesting to see how
it looks like, and also dosemu2
follows the simple coords scheme
in that case, that is found in other
emulators. Complex scheme is
only active when cursor is invisible.

@javispedro
Copy link

I didn't think it was possible (cursor rendering is done by video driver on 3.x and that's quite a beast).
But maybe it is possible by calling HideCursor() a lot of times.
And probably could even use GetCursor to fetch the shape and convert it to an int33 shape.
And need to think of a way to check if the int33 driver can render the cursor (at the current video mode).
Sounds interesting.

@stsp
Copy link
Member

stsp commented Apr 21, 2022

Ah, as far as I can recall, we
do not support cursor shape in
an ungrabbed mouse mode.
But that's likely not a big problem.

@NattyNarwhal
Copy link

@javispedro Unrelated but since we're on the same thread, regarding:

VMware shared folders support is interesting, but there is very little documentation that I can find, no sample code, and no open source implementation.

in your repo, I believe there's a VMware HGFS client in [https://sites.google.com/site/chitchatvmback/vmtools](this guy's source for various utilities), some of which work on DOS, though it's quite old. Unfortunately when I last tried it, it didn't work with modern Workstation for some reason.

@javispedro
Copy link

I believe there's a VMware HGFS client in [https://sites.google.com/site/chitchatvmback/vmtools](this guy's source for various utilities), some of which work on DOS, though it's quite old. Unfortunately when I last tried it, it didn't work with modern Workstation for some reason.

Found another VMware client http://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/repositories/1.3/pkg-html/vmsmount.html , this one from FreeDOS. It's also Watcom C and quite decently written. I really could have used it while writing mine. We really need a better catalog of DOS software :)

@stsp
Copy link
Member

stsp commented May 21, 2022

@javispedro I am getting certificate
expired error from this link:
https://depot.javispedro.com/vbox/vbados/vbados.zip

@javispedro
Copy link

@javispedro I am getting certificate expired error from this link: https://depot.javispedro.com/vbox/vbados/vbados.zip

Should be fixed (first time certbot setup for that machine...).

@stsp
Copy link
Member

stsp commented May 21, 2022

Thank you.
It was for quite long btw.
I was initially hoping it would
fix itself. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants