cristianbuse / VBA-UserForm-MouseScroll

Use the Mouse Scroll Wheel to scroll VBA UserForms and Controls
MIT License
69 stars 11 forks source link

Choppiness and interesting behavior when trying to directly shift focus from one open userform to another #44

Closed wodue closed 4 days ago

wodue commented 2 months ago

Hey cristian. First and foremost, thanks a million for this cool project. I still don't know why Windows would not just have scrolling built into the boxes as an attribute or something.

I tried out the code our project (we are running the code in AutoCAD2024) and it was working great. However, when I started having multiple windows open and wanting to shift focus between them something very specific happened. It happened when I tried to click the top bar of the unfocused userform to immediately move it (i.e. like with other windows if they don't have focus - you click and hold on the top bar, the form gets focus and you can immediately move the form around the screen). The form I wanted to move did get focus, however, after that the entire application became unresponsive, but it was still running, nothing had crashed. Everytime that happens I can press the Esc key and that seems to get it out of that state. The form that I was focused on does not have any scroll controls, and the form I want to focus and move immediately after focus has many scrollable controls (mostly comboboxes).

To work around this issue,

Please let me know if I can provide any other information, fixing this would greatly help us with our project too. Thank you for your help and attention.

wodue commented 2 months ago

My initial suspicion was that it has something to do with the top bar not actually being part of the userform? Because when I hover over the top bar the MouseMove event for the form is not fired unlike when I hover over some section below the top bar.

cristianbuse commented 2 months ago

Hi @wodue ,

Thank you for the kind words and feedback!

I cannot replicate the behaviour. Tried moving a second form (no scrollable controls and no focus) and works fine.

Can you provide me with a minimal example to reproduce this? Thanks!

wodue commented 2 months ago

Thank you for your quick response! I must investigate this issue further - I just realized it might be something in my code. The issue I mentioned seems to only be limited to two of my userforms - They both have combobox controls on them. I.e. When I try to click on the top bar to immediately move them, like explained above, from anywhere outside the form, the mouse becomes unresponsive not only in AutoCAD but on my entire machine.

wodue commented 2 months ago

Sorry my bad, im new to commenting on github.

cristianbuse commented 2 months ago

I would suggest that you try to comment out all the EnableMouseScroll... lines and try to see if the issue occurs. We would at least know if the issue is caused by my library or not.

wodue commented 2 months ago

Commented all EnableMouseScroll calls and I can switch between all my forms again no problem. I wonder if it has something to do with me hiding the form when pressing the [X] in the top left corner of the form instead of terminating it. That being said, I did put DisableMouseScroll everywheres where the form is losing focus to be safe.

cristianbuse commented 2 months ago

I never terminate the form - meaning I never call Unload. I always Hide and make sure I set all instances to Nothing if I do not need the form. VB will take care of terminating the form later on, sometimes with some delay. I do this because of a bug that causes crashes when using Unload, and have stopped using it since 2019. I did not notice any issues with the scroll while hiding.

Does calling DisableMouseScroll solve the issue?

wodue commented 2 months ago

DisableMouseScrolldoesn't solve the issue sadly. But it is good to know that hiding the form instead of terminating it should not affect it. Could terminating the forms through the normal UserForm_Terminate event may affect it?

So far the problem seems to be only in two specific UserForms. I am currently trying to figure out what the difference is between those two UserForms and the rest of them.

When the issue occurs, the form in question gains focus, but the mouse becomes virtually 'disabled'. Can only move the mouse around, no response from the screen or icons the mouse hovers over.

I have very little knowledge with Windows hooks and am just getting started with the topic, but could it be that the mouse is hooking onto something that 'isn't there'? I'm thinking that is why I can get out of the 'disabled' state by pressing the escape key on my keyboard (maybe resetting something in the hook chain?? But then again I thought all hook chains were separate so probably not), this is just a thought.

wodue commented 2 months ago

Cristian I gathered more information.

It seems as so that the MouseProc function actually gets stuck in a loop. I don't know how but I can explain how I came to the suspicion.

When opening the userform the normal sequence of events happens (Initialize then Activate). Opening another form with the first one being open and focusing and working with that other form, also no problem. The problem happens when wanting to switch back focus to the old form and wanting to move it. In the forms UserForm_Activate I have it reposition itself on a certain part of the screen and then it goes back to where it was before (for debugging purposes). When I do it with disabled Mouse Scrolling, you can see the form quickly flash when repositioning and immediately going back to the position it was in before. When trying to focus back with enabled Mouse Scrolling, the form gets stuck in the position that it should only be in for a split second. This leads me to think that it has something to do with the mouse hook not being 'released' and therefore the MouseProc acting in an unwanted infinite loop way?

wodue commented 2 months ago

Update:

I isolated an infinite loop - Not moving my mouse while debugging:

From MouseProc it seems to cycle through ProcessMouseData, Property Let IsAsyncCallback and Class_Terminate.

If I don't move my mouse and step through it quickly it keeps on going that path. Sometimes, randomly (I'm guessing when I accidentally move my mouse by the tiniest bit) it seems to break out but only after cycling through it a couple times. Reason I think that is, when I try to manually break the code with CTRL+fn+Break the code will only break when I move my mouse after giving the break command. If the mouse isn't moved the code won't even break, making it tough to debug.

Could I maybe add some logic in the ProcessMouseData Function to not make it cycle? Like a conditional statement that recognizes when a new form is focused with WM_RBUTTONDOWN? Asking for advice because Windows hooks are magic to me still and no one can tell me otherwise.

cristianbuse commented 2 months ago

@wodue

This is great info. I was able to replicate the issue by pressing Ctrl+Break while the VBE window was active.

I will try to find a solution and will let you know. Thanks!

cristianbuse commented 2 months ago

Very interestingly - the Ctrl+Break behaviour that stops all form events is not related to the mouse hook. I've just tried Ctrl+Break on a form with no mouse hook and the behaviour is exactly the same - I cannot even close the form anymore via the X button. This happens for Modeless display only.

cristianbuse commented 2 months ago

@wodue

When you're trying to move the second form but it gets stuck, can you please let me know what the Locals window status is? For example: image

image

wodue commented 2 months ago

@cristianbuse That is very interesting. I'll have to try breaking it without your module enabled too, that didn't happen for me yet. In fact when I turned it off it seemed to be working again. I currently am sick and away from my workstation, once I get back to it I'll look further into it 👍🏻

wodue commented 2 months ago

@cristianbuse I appreciate you still looking into the issue with me, even though it does not technically concern your code anymore 🙏🏻

cristianbuse commented 2 months ago

@wodue

Absolutely. I want to improve my repositories as much as I can and sometimes I cannot do it without feedback from users like you. So, thank you, and get well soon!

wodue commented 2 months ago

@cristianbuse Back at it today. When I Ctrl+Fn+Break the code right after the bug happened, the code will not stop, if I don't move my mouse. Once I ever so slightly move the mouse, the code breaks and a vba window pops up saying Code execution interrupted. On there I press the debug button and then I can step through. The locals window status when I get out of the pop-up vba window says basMouseScroll.MouseProc

wodue commented 2 months ago

If i DON'T manually break the code, the locals window is telling me that the code is still running even though the windows seem frozen. I.e. it says <ready> when I don't move my mouse and it says <running> when I move the mouse.

wodue commented 2 months ago

Another new thing I found out: When you cycle to another application (,while the forms are frozen,) with Alt+Tab and cycle back to the frozen application, it will unfreeze and work like normal again.

cristianbuse commented 1 month ago

@wodue

The problem is that once I detect the VBE being enabled, I turn the m_needsActivation flag to True and do not hook back the mouse - the idea is to hook back on a Mouse Move event (see SetHoveredControl) - but because the events are somehow disabled on the form, the call to ShowWindowAsync never happens (inside SetHoveredControl).

I cannot use the hook itself to fix this (e.g. rely on WM_RBUTTONDOWN) because that is exactly what I am trying to avoid. While the VBE is active, the hook must be off, otherwise I reintroduce issues that were fixed by the introduction of m_needsActivation.

Since, the form events stop firing independetly from the mouse hook (e.g. Ctrl+Break), there isn't a direct way for me to fix this. Maybe a timer async call but I wouldn't want to go down that rabbit hole.

Will investigate further, thanks for the feedback so far.

wodue commented 1 month ago

@cristianbuse

Thank you for the investigation report so far. It's still tough to understand for me, but you explaining the issue in that much detail really does help a lot!

wodue commented 1 month ago

@cristianbuse

So do I understand right so far that the main cause for the issue is that the VBE window is open? I.e. would the issue be there if you were to just run it normally without the VBE window?

cristianbuse commented 1 month ago

@wodue ,

Yes, you understood correctly. I added code specifically to deal with the VBE window because of issue raised in #34

I guess the issue would not happen without activating the VBE window but please try it yourself.

wodue commented 1 month ago

@cristianbuse

I tried out if it works without the VBE window being activated or being open. Sadly the issue persists (, and I wasn't able to debug since the VBE window was closed)

cristianbuse commented 1 week ago

Hi @wodue ,

Could you please re-test using the latest version and see if the issue still occurs? Thanks!