I have some code that seems to have an error. I didn't write it, in fact it is in c++ and until a few weeks ago I have never written any code in c++.
We have a keyboard for a touch screen that we bring up when keyboard entry is required and closed when it is not. Our software can be used on a kiosk without a physical keyboard using that touch screen keyboard we developed years ago (limited to a-z,0-9, enter, shift, tab).
The keyboard is "behind" the application on some computers with Windows 7 (might be others but have not see the problem on other OS's).
Worked for years. I updated other parts to finally work with Windows 7, now on 66% of our windows 7 installs the keyboard doesn't come up at all (is behind the application). On my computer at first I thought it came up 100% of the time, but continued testing found it comes up 95-99% of the time, making it difficult to trouble shoot.
In addition most of the posts about GetForegroundWindow() have to deal with sending or getting messages to and from other application, not about layering applications (like I need).
When I started the code looked like this:
bool ShowKeyBoad(bool Show)
{
int WizHeight = 422;
int KeyWidth,KeyHeight,KeyLeft, KeyTop;
AnsiString Params;
AnsiString ShowFile = GetFullPath(GetExeDir(), "OnscreenKeyboard.exe");
AnsiString HideFile = GetFullPath(GetExeDir(), "bkecekeyboard.exe");
KeyHeight = Screen->Height - WizHeight;
KeyWidth = Screen->Width;
if (KeyWidth > Screen->Width)
KeyWidth = Screen->Width;
KeyLeft = (Screen->Width - KeyWidth) / 2;
KeyTop = (Screen->Height) - KeyHeight;
Params = "x-" + IntToStr(KeyLeft) + " y-" + IntToStr(KeyTop) +
" h-" + IntToStr(KeyHeight) + " w-" + IntToStr(KeyWidth);
if (Show)
{
HWND Hand= GetForegroundWindow();
ShellExecute(NULL, "open", ShowFile.c_str(), Params.c_str(), NULL, SW_SHOWNORMAL);
Sleep(100);
SetForegroundWindow(Hand);
SetActiveWindow(Hand);
}
else
ShellExecute(NULL, "open", HideFile.c_str(), "/stop", NULL, SW_HIDE);
return true;
}
I have tried a few things.
Capturing the HWND of the ShellExecute and passing that to SetActiveWindow(ShellHand) seemed to have some effect. But still not consistent.
HWND shellHand = ShellExecute(NULL, "open", ShowFile.c_str(), Params.c_str(), NULL, SW_SHOWNORMAL);
Adding Sleep(25) before HWND Hand= GetForegroundWindow(); had the best affect on the GUI - but I don't want to rely on timing it just right.
Various internet search pointed me to some code that also seemed pretty good. But it changes registry settings, and that doesn't seem to be a wise choice.
With that solution we change SetForeground to SetForegroundInternal
void SetForegroundWindowInternal(HWND hWnd)
{
if(!::IsWindow(hWnd)) return;
//relation time of SetForegroundWindow lock
DWORD lockTimeOut = 0;
HWND hCurrWnd = ::GetForegroundWindow();
DWORD dwThisTID = ::GetCurrentThreadId(),
dwCurrTID = ::GetWindowThreadProcessId(hCurrWnd,0);
//we need to bypass some limitations from Microsoft :)
if(dwThisTID != dwCurrTID)
{
::AttachThreadInput(dwThisTID, dwCurrTID, TRUE);
::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,0,&lockTimeOut,0);
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,0,SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::AllowSetForegroundWindow(ASFW_ANY);
}
::SetForegroundWindow(hWnd);
if(dwThisTID != dwCurrTID)
{
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,(PVOID)lockTimeOut,SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::AttachThreadInput(dwThisTID, dwCurrTID, FALSE);
}
}
update guessing that Hand = NULL is my problem I made the code look like this:
bool ShowKeyBoad(bool Show)
{
int WizHeight = 422;
int KeyWidth,KeyHeight,KeyLeft, KeyTop;
AnsiString Params;
AnsiString ShowFile = GetFullPath(GetExeDir(), "OnscreenKeyboard.exe");
AnsiString HideFile = GetFullPath(GetExeDir(), "bkecekeyboard.exe");
KeyHeight = Screen->Height - WizHeight;
KeyWidth = Screen->Width;
if (KeyWidth > Screen->Width)
KeyWidth = Screen->Width;
KeyLeft = (Screen->Width - KeyWidth) / 2;
KeyTop = (Screen->Height) - KeyHeight;
Params = "x-" + IntToStr(KeyLeft) + " y-" + IntToStr(KeyTop) +
" h-" + IntToStr(KeyHeight) + " w-" + IntToStr(KeyWidth);
if (Show)
{
HWND Hand;
int intfail=1000; // count down seems correct in this case, usually don't
while (Hand = NULL)
{
if (intfail <=0)
break;
Hand = GetForegroundWindow();
intfail--;
}
if (Hand == NULL)
{
// Send Message to screen giving instructions to try again
return false;
}
ShellExecute(NULL, "open", ShowFile.c_str(), Params.c_str(), NULL, SW_SHOWNORMAL);
Sleep(100);
SetForegroundWindow(Hand);
SetActiveWindow(Hand);
}
else
ShellExecute(NULL, "open", HideFile.c_str(), "/stop", NULL, SW_HIDE);
return true;
}
Appears to solve the problem.