Introduction
I recently faced a problem while developping a Windows Mobile 6.5 application in .NET Compact CE with handling input events. Since it was hard to find a solution on the internet, I thought it was a good idea to share my experiences so that other developers getting into the same problems have less trouble on this item.
Situation
My problem was as follows. My forms application calls a webservice to check the credentials the user entered and load some data to show. While executing, I show the waitcursor.
Cursor.Current = Cursors.WaitCursor
This will be enough hints for the end-user to know he has to wait until something happens, so was my (naive) thought. But then the trouble started after I found an impatient collegue willing to test my application.
Problem
While the executing process (checking credentials, loading data) can last more than 5 seconds, my impatient collegue started to produce mouse clicks after about 2 seconds.
This resulted in click events in the screen shown after the webservice executing was done. Of course, this is not what I intended! After all, setting the waitcursor just sets the waitcursor, nothing less, nothing more. Therefore, I tried to disable the form, show a loading screen, etc, but none of them were sufficient in suppressing the mouse and key events.
What in fact happened was the user input is buffered by the OS and fired
after the new form is activated. So that is the place where we have to deal with the problem.
Solution
I created a sealed class called
InputEvents
which can be called on in the activate event of a form, and suppresses all unhandled input events done before the form was actually activated.
public sealed class InputEvents
{
internal struct MSG
{
public IntPtr hwnd;
public int Msg;
public IntPtr wParam;
public IntPtr lParam;
public int time;
public int pt_x;
public int pt_y;
}
[DllImport("coredll.dll", EntryPoint = "PeekMessage", SetLastError = true)]
private static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
[DllImport("coredll.dll", EntryPoint = "GetMessageW", SetLastError = true)]
private static extern bool GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
[DllImport("coredll.dll", EntryPoint = "TranslateMessage", SetLastError = true)]
private static extern bool TranslateMessage(out MSG lpMsg);
[DllImport("coredll.dll", EntryPoint = "DispatchMessage", SetLastError = true)]
private static extern bool DispatchMessage(ref MSG lpMsg);
private const int WM_KEYFIRST = 256;
private const int WM_KEYLAST = 264;
private const int WM_MOUSEFIRST = 512;
private const int WM_MOUSELAST = 521;
private const int PM_NOREMOVE = 0;
private const int PM_REMOVE = 1;
public static bool SuppressKeyMouseEvents()
{
MSG lpMsg;
while (PeekMessage(out lpMsg, IntPtr.Zero, 0, 0, PM_NOREMOVE))
{
if (GetMessage(out lpMsg, IntPtr.Zero, 0, 0))
{
if (!((WM_MOUSEFIRST <= lpMsg.Msg && lpMsg.Msg <= WM_MOUSELAST) || (WM_KEYFIRST <= lpMsg.Msg && lpMsg.Msg <= WM_KEYLAST)))
{
TranslateMessage(out lpMsg);
DispatchMessage(ref lpMsg);
}
}
}
return true;
}
}
More information can be found at
http://msdn.microsoft.com/en-us/library/ms907610.aspx[
^].