NattyNarwhal / vmwmouse

VMware mouse driver for Windows 3.1
336 stars 13 forks source link

Third button and wheel #5

Open NattyNarwhal opened 2 years ago

NattyNarwhal commented 2 years ago

For third button: The DDK drivers don't include an example with one, nor does mouse.inc provide any insight into how you'd expose a third button to the event procedure. Maybe just the same pattern as i.e. SF_B2_UP?

For wheel: Not sure what we could do. Post WM_VSCROLL events to the active window? That seems ultra crumbly from a driver though, though there may be an example non-VMM driver that does it.

We'd probably need to get rid of the other drivers that are now dead weight in mouse.drv.

NattyNarwhal commented 2 years ago

For my notes: the comm and network driver seem to call the post message. It may be safe, but we're also doing it from an interrupt handler, and we might not know the state of USER.

FeralChild64 commented 2 years ago

I hope you'll continue working on your driver - I'm making progress with relevant DOSBox Staging patch, mouse wheel seems to work :)

https://github.com/FeralChild64/dosbox-staging/commits/fc/vmware-mouse-1

javispedro commented 2 years ago

I took a look at what the "4D mouse" driver mentioned in the dosemu thread is doing. Apparently they have a hook .DLL , so the mouse driver itself is only posting a single event that the hook DLL reads later on, and transforms into the corresponding WM_*SCROLL events.

In the hook DLL there is some logic to try to find the target for the WM_SCROLL message. I will describe it a bit (mostly gathered from using winspy.exe so logic may be incomplete):

First we take the window under the position of the mouse. If the window style is "WS_VSCROLL" (i.e. scrollable), then we send a WM_VSCROLL message to this window and exit If the window style is "WS_HSCROLL", then we send a W_HSCROLL message and exit Now we try to look into the children window of the window. if we find a child window with class "ScrollBar" (the standard win16 scrollbar control), then we send a WM_VSCROLL to the parent window. If we didn't find anything, we go to the parent window and try again (i.e. in case the mouse cursor ended up in a smaller sub-window).

I tried this logic in my driver and seems to work for filemgr and write, the two programs shown in the demo: (forgive the gratuitous spanish edition win3.x).

https://user-images.githubusercontent.com/123961/163279165-51e20586-6225-4fb4-a002-35de11cca853.mp4

However calling all these USER functions from the interrupt handler seems like very risky, so maybe the hook DLL solution is better (and would allow for writing it in C, and would allow for reuse between different drivers).

Also note that there is a big problem with using (real hardware) wheel mouse under protected mode Windows: VKD.386 (yes, VKD, not VMD) is virtualizing the PS/2 mouse, and it basically ignores all the PS/2 intellimouse initialization packets/knocks. Therefore from a win16 driver the wheel is just inaccessible. Same problem with VirtualBox, since I also have to enable intellimouse mode in order to receive wheel data. So wheel mouse is impossible there too (unless we override VKB somehow). VMware does not have this problem (you can get wheel data at any time using the backdoor), nor do the DosBox forks (since they have a builtin int33 driver that is native code and thus "outside" protected mode Windows, so you can always access the wheel via int33 ---- this is what I do in the video).

NattyNarwhal commented 2 years ago

I actually have the wheel logic implemented in vmwmouse, but it just blithely fires WM_VSCROLL events You can reveal some pretty amusing bugs. Checking if the entity is even scrollable would definitely be better.

It also seemed a little unstable, which is why I gated it behind an INI option. You're right moving it to a DLL would probably be a lot easier.

javispedro commented 2 years ago

I actually have the wheel logic implemented in vmwmouse, but it just blithely fires WM_VSCROLL events You can reveal some pretty amusing bugs.

Yeah I did try it and saw how you can scroll the contents of program manager into oblivion :)

zapolnov commented 2 years ago

Microsoft IntelliMouse used RegisterWindowMessage API to setup and retrieve a global wheel message. You have to make the following call to obtain message ID:

wheel_message = RegisterWindowMessage ("MSWHEEL_ROLLMSG")

This message become WM_MOUSEWHEEL in later versions of WIndows.

I am not sure if this will work with Program Manager, but at least it should work properly with apps written with MS IntelliMouse support in mind.

Would it be possible to add support for this message into the driver?

NattyNarwhal commented 2 years ago

Oh, so basically, we'd register the same message and send it out with the compatible params, and just lean on the MS wheel mouse software for 3.x? That seems doable. The current approach (vmwmouse basically implements the bare minimum; I believe Javiar's driver is a lot more careful with sending messages) might be better because it'd work without additional software though. (For 9x when wheel matters more, I suspect this should be rewritten to be a VMD anyways - the 95 DDK has such an example.)

zapolnov commented 2 years ago

The message was not handled by MS code, but directly by software that supported mouse wheel. What I mean is that mouse driver just sent this message to the current active window and then the app's window procedure directed it to the correct control if it knew about the message (see Raymond Chen's blog post I linked below).

Browsing through archives shows that this message was the official way of implementing wheel support in Windows 3.1, Windows NT 3.5 and early Windows 95. There was an official "zmouse.h" header with the corresponding defines (e.g. MSH_MOUSEWHEEL is defined to be a string "MSWHEEL_ROLLMSG"). So I would expect at least some of Win 3.x and Win32s software to support this message natively.

It would be nice to have a compile-time or run-time option in vmwmouse to send this message. If you are already sending WM_VSCROLL, should it be possible to change it to send a registered value of MSWHEEL_ROLLMSG instead?

Interestingly, there are actually three messages int the "zmouse.h". The other two allow to check for wheel support and to get number of lines to scroll at one step. Here is what I found in zmouse.h in MinGW:

HWND hw = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
*puiMsh_MsgMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL);
*puiMsh_Msg3DSupport = RegisterWindowMessage(MSH_WHEELSUPPORT);
*puiMsh_MsgScrollLines = RegisterWindowMessage(MSH_SCROLL_LINES);
*pf3DSupport = (*puiMsh_Msg3DSupport ? (WINBOOL)SendMessage (hw, *puiMsh_Msg3DSupport, 0, 0) : FALSE);
*piScrollLines = (*puiMsh_MsgScrollLines ? (int)SendMessage(hw, *puiMsh_MsgScrollLines, 0, 0) : 3);
return hw;

More information can be found here:

https://devblogs.microsoft.com/oldnewthing/20080806-00/?p=21353 (Raimon Chen's post on the topic)

https://web.archive.org/web/20070913110322/http://msdn2.microsoft.com/en-us/library/ms645617.aspx (Archived copy of MSDN article on WM_MOUSEWHEEL, which includes a subsection about MSWHEEL_ROLLMSG)

https://github.com/open-watcom/open-watcom-v2/blob/master/bld/w32api/include/zmouse.mh (zmouse.h from OpenWatcom)

https://chromium.googlesource.com/chromium/deps/perl/+/refs/heads/main/c/i686-w64-mingw32/include/zmouse.h (zmouse.h from MinGW)

javispedro commented 2 years ago

Is there any (freeware) program that actually understands the MSWHEEL_ROLLMSG message, for testing? A quick grep for MSWHEEL reveals nothing in my library.

javispedro commented 2 years ago

As far as I can see, this was for Windows 95 exclusively. The first MS wheel mouse listed 95 as the minimum required OS, and starting from 98 there was already support for the standard WM_MOUSEWHEEL messages. So while it is possible that some post-95 program for 3.x did implement support for these zmouse messages by accident, it looks like it would have been very rare.

I did find a copy of the intellimouse driver for w95 from my old MS explorer. It does contain mswheel.exe and mswheel.dll; however It does not seem to send the MSWHEEL messages (or at least spy++ does not pick them up). Anyway, I'm not sure -- the driver is not period correct since the intellimouse explorer is 99ish. However, the wheel does work with this driver under win95 (osr2) in many programs including ancient 3.x programs. It seems that it implements wheel support by extensive use of hooks -- those hooks try to scroll the windows by itself even in programs which did not support any wheel messages, not dissimilar to what vmwmouse/vbmouse is already doing.

Which actually makes a lot of sense, since otherwise the wheel would only be usable in a small number of programs.

In fact, with the mswheel.dll hooks, wheel support is actually better on 95 than it is with the native wheel support in win98. A very immediate example: device manager is wheel-scrollable with the hooks on win95osr2, but NOT wheel-scrollable at all with the native wheel support on win98se. Likewise for all 3.x binaries since they don't have native wheel support but do work with the hook under win95.