How do I reconcile Sendmessage, SendInput, Mouse_event blocked by Getasynckeystate? - c

TL;DR:
I need to use both sendmessage and sendinput in order to get into an old function/event in a program that I can't re-build. While in there, I can't release the virtual mouse click using any of the methods I used to get in there in the first place - they're ignored.
Any other way to trigger the mousedown event - one where I could also release the mouse click might work.
I am writing a program that has to interact with a black-boxed old piece of software written in VB6 long long ago.
My program has to be able to send mouse clicks, specifically mousedown and mouseup events to the old program.
Here's the tricky part...
The mousedown event in the old program uses:
While GetAsyncKeyState(1)
Wend
to wait for the user to release the mouse.
Currently, in order to get the event to trigger, I need to use:
SendMessage(control_handle, WM_LBUTTONDOWN, 0, 0);
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1,&Input,sizeof(INPUT));
This does trigger the event (using just sendmessage does NOT trigger a necessary branch inside the event because that branch is entered with a GetAsyncKeyState(1) test as well), but issuing any combination of the following does NOT release the mouse click:
SendMessage(control_handle, WM_LBUTTONUP, 0, 0)
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1,&Input,sizeof(INPUT));
The code just keeps repeating in the while/wend part, it never gets out. The release code is being sent, but GetAsyncKeyState(1) isn't recognizing it as a mouse release. SUPER weird that GetAsyncKeyState(1) recognizes the function as a mouse down event, but GetAsyncKeyState(1) won't recognize as a mouse up.
What I've tested:
Clicking the real mouse elsewhere on the screen does release the
function.
Removing the sendmessage call, and using just the sendinput function
(and manually positioning the mouse over the object that needs
clicking) DOES work to release the loop.
I can't rely on the user not messing with the mouse while this is
doing its thing, so I'm hesitant to have the code virtually move the
mouse over the button to be clicked.
I've tried the deprecated mouse_event function as well, same exact
behavior.
Timing is critical. There can't be substantial delays between the trigger is issued and when it happens. Think keyboard-response speed.
I wrote a very simple VB6 program to simulate the while/GetAsyncKeyState(1)/wend loop to test this out on, and the behavior is the same - so I can be confident there isn't something weird in the old program that is causing this to happen.
Thank you very much for reading and helping!

In case this ever comes up for anyone else ever.... Using postmessage instead of sendmessage allows the program to continue on. Makes sense, really..

Related

Getting Debugger To Break On Next Event

In the Visual Basic 6.0 IDE, it was possible to break a running program that is sitting idle (waiting for an event on the UI thread) then hit F8 (single step). After that, any click, mouse-over, or other event that led to code would cause the debugger to break on the next line of code to execute, which would be the first line of code in the event handler. For example, if you showed a data-entry form with an OK button on it, you could break that form when idle, hit F8, then click the OK button. The debugger then would highlight the first line of code in the cmdOK_Click event handler.
Is there a way to do the above in Visual Studio 2017 with a C# Winforms project? I have seen similar posts on SO that instruct to break all (Ctrl-Alt-Break) then hit F11 (step into) then click a button on the form. But that isn't working. When I hit F11, the program goes back into running mode and events are processed without causing the IDE to break and show the first line to execute after the event.
Note that in the VB6 IDE when you break a program then hit F8 any event that fires afterwards and leads to an event handler will cause the IDE to break. I am looking for similar behavior for the VS 2017 IDE and a C# Winforms program.
Note: Please don't suggest to go into every even handler and set a breakpoint on the first line of code--consider that a complex program might contain thousands of event handlers, so setting breakpoints within each is not a practical (or elegant) solution.
Both F10 (Step Over) and F11 (Step Into) provide the desired behavior, but only if Enable Just My Code option is on:

WPF's command firing twice on fast doubleclick

From a production application, we notice that our WPF buttons fire the ICommand.Execute method twice on fast double click.
Now, on every Command, the application is covered with a full-screen spinner animation, preventing any further interaction with the application.
This github repo contains a minimalistic repro of the issue. Note that:
when the Button's Command fires, the "IsBusy" flag is set to true
as a consequence, the BusyIndicator overlay will be shown
as a consequence, the Button cannot be pressed again until after 300ms
However, especially on slow computers, when fast double-clicking (really fast, like gaming fast that is), it is possible to fire the command twice without the BusyIndicator blocking the second call (this can be seen if the output shows 2 'click' lines right after one another).
This is unexpected behavior to me, as the IsBusy flag is set to true right away on the UI thread.
How come a second click is able to pass through?
I would expect the IsBusy Binding to show the overlay on the UI thread, blocking any further interaction?
The github sample also contains 2 workarounds:
using the ICommand.CanExecute to block the Execute handler
using the PreviewMouseDown to prevent double clicks
I'm trying to understand what the issue is.
What work-around would you prefer?
Diagnosis
This is only my guess and not a solid and confirmed info, but it seems that when you click the mouse button, the hit-testing is done immediately, but all the mouse related events are only scheduled to be raised (using the Dispatcher I presume). The important thing is that the control that is clicked is determined at the time the click occurred, and not after the previous click has been completely handled (including all UI changes that potentially follow).
So in your case, even if the first click results in showing the BusyIndicator covering (and thus blocking) the Button, if you manage to click for the second time before the BusyIndicator is actually shown (and that does not happen immediately), the click event on the Button will be scheduled to be raised (which will happen after the BusyIndicator is shown), causing the command to be executed again even though at that point the BusyIndicator will possibly be blocking the Button.
Solution
If your goal is to prevent command execution while the previous one is still executing the obvious choice is to make the Command.CanExecute result depend on the state of the IsBusy flag. Moreover, I wouldn't even call it a workaround, but a proper design.
What you're facing here is a clear-cut example of why you shouldn't make your business logic rely on UI. Firstly, because rendering strongly depends on the machine's processing power, and secondly because covering a button with another control by far does not guarantee the button cannot be "clicked" (using for example UI Automation framework).

How to simulate click/tap in Codename One?

I am writing a test in Codename One, in which I want to simulate click anywhere on the screen, since I want to check that a certain dialog is hidden. I tried to simulate the click using press and release:
form.pointerPressed(2, 2);
form.pointerReleased(2, 2);
But it did not work in the tests, nothing happened.
pointerPressed and pointerReleased, but not called on the form, but on the Display, was the correct thing to do. I guess that the form I was trying to click was not accessible because of the blocking dialog.
Display.getInstance().pointerPressed(x, y);
There are many things that can cause that.
That specific dialog might not be dismissible with pointer out of bounds touch.
That point might be problematic for some reason e.g. might be in the status bar
The dialog might still be showing since the EDT needs to be flushed with callSerially
The code might not be reachable since the dialog blocked some execution due to invokeAndBlock

How to clear keyboard buffer from stale messages

My WinForms application has a button. This button has accelerator key (e.g. Alt+L). When button is pressed I handle the Click event and disable UI to prevent further button clicks until processing is finished. However, when accelerator key is pressed using keyboard those keystrokes are queued and get processed as soon as UI is enabled again. I don't want this. My question is how to clear/flush keyboard buffer?
If I use KeyPress or KeyDown to eat those characters I don't know when they have been received. I only want to suppress old/stale messages that arrived when I was still processing first Click event.
Yes, indeed your theory of the problem is consistent with that proposed by both myself and madmik3 in the comment exchange above. The amount of work your application is doing on the UI thread is effectively blocking it from processing other events, including keystrokes by the user. Those are getting queued for later execution whenever your application finishes its time-consuming foreground task. Those are the perils of a modern-day, pre-emptive multitasking OS. Of course, without posting your actual code, the best I or anyone else can do is speculate about what the problem is, given our experience.
The quick check to confirm that this is actually the case is to toss Application.DoEvents into your processing loop. That will allow the OS to handle the keystrokes immediately, which will all fail because the button has been disabled. (Click events, whether initiated by the mouse or keyboard shortcuts, are not raised for a Button control that has its Enabled property set to "False".) This is the closest you'll get to anything like "flushing the buffers". I doubt you're receiving KeyDown or KeyPress events anyway until after whatever long-running task has completed.
If that fixes the problem, the long-term solution is to spawn a new thread and perform whatever processing you need to do there, instead of on your UI thread. This will prevent you from blocking your UI thread, and, assuming the Button control is correctly disabled, cause the keystrokes to get thrown away because the button they "click" is in a non-clickable state. The simplest way to create a new thread is using the BackgroundWorker component. The documentation contains a pretty good example.

UIElement.PreviewMouseMove or not MouseMove... that is the question

WPF,
MSDN:
UIElement.PreviewMouseMove Event
Occurs when the mouse pointer moves
while the mouse pointer is over this
element.
As I can see, this is not true... When I PreviewMouseDown, then PreviewMouseUp, an PreviewMouseMove event interferes. Is this a bug in Framework or MSDN documentation leak?
I just need to differentiate when a element really moves, and this "static" "Move" breaks my logic...
Function calls log:
Function: MyCanvas.OnPreviewMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs), Thread: 0x6F4 Main Thread
Function: MyCanvas.OnPreviewMouseMove(System.Windows.Input.MouseEventArgs), Thread: 0x6F4 Main Thread
Function: MyCanvas.OnPreviewMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs), Thread: 0x6F4 Main Thread
Function: MyCanvas.OnPreviewMouseMove(System.Windows.Input.MouseEventArgs), Thread: 0x6F4 Main Thread
The previous log was obtained when obtaining also the DoubleClick event, so, I don't suppose I moved the mouse even by a micrometer...
Using simple handlers I was able to get PreviewMouseUp and PreviewMouseDown (and LeftButtonUp/Down) events to fire reliably without MouseMove interfering. I suspect that the behavior you're seeing is because, especially with modern high resolution mice, it's impossible to not move the mouse (even very slightly) while clicking it. Actually, it would be very foolish to assume your users won't do that. There's nothing preventing the user moving the mouse while keeping the mouse button pressed.
If you want to register the event sequence only if the mouse is stationary, record the position on mouse down and only do your actions on mouse up if the position changed significantly.

Resources