I want to do a thing conceptually simple as this: For every control that accepts keyboard input(CEdit, CCombobox with Editable text, etc.), when the control is focused and enabled, make the On Screen Keyboard appear. Preferably with accessibility support (I've done some reading about Microsoft User Interface Automation) rather than calling directly the osk.exe utility.
A thing very like the touchscreen smartphones when the user puts the focus on an editable control.
UPDATE: If there is a Windows option that can make the On Screen Keyboard to behave the way I describe that's just fine!
UPDATE 2: The thing I want is similar to http://msdn.microsoft.com/en-us/library/windows/apps/hh465404.aspx , but in Windows 7.
I had done experiments with the IUIAutomation class, calling directly osk.exe when focusing an editable control, and closing that window when focusing a non-editable one.
But, I still have three problems:
1) When opening a CFileDialog application becomes unresponsive. The same is happening for only another Modal Dialog of the application (in every other Modal Dialog everything works fine). I discovered that CFileDialog opens some background threads and my only problematic modal too. I suspect this has to do with threading issues.
2) When some other control is focused, and thereafter I click directly the DropDown button of a CBS_DROPDOWN combobox, not picking on its edit control, I see a flash of OSK appear and disappear. Using Spy++ and UIA Inspect I got the suspicion of the text edit being focused before the combobox goes to the dropped state.
3) After doing some experiments with SetWindowPos, MoveWindow
::MoveWindow(osk_wnd->m_hWnd, LeftOsk, TopOsk, -1, -1, FALSE);
Or
osk_wnd->SetWindowPos(NULL, LeftOsk, TopOsk, -1, -1, SWP_NOSIZE | SWP_NOACTIVATE);
and using also some message processing experiments like
//osk_wnd is a CWnd* variable that represents OSK main window
osk_wnd->PostMessage(WM_SYSCOMMAND, SC_MOVE + HTCAPTION, MAKELPARAM(point.x, point.y));
Or
POINT point = {0};
GetCursorPos(&point);
SendMessage(osk_wnd->m_hWnd, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y));
SendMessage(osk_wnd->m_hWnd, WM_NCMOUSEMOVE, HTCAPTION, MAKELPARAM(LeftOsk, TopOsk));
GetCursorPos(&point);
SendMessage(osk_wnd->m_hWnd, WM_NCLBUTTONUP, HTCAPTION, MAKELPARAM(LeftOsk + point.x, TopOsk + point.y));
I could not move the OSK window. It is important that I can move it; otherwise, it will appear covering the focused control, and the user can not see the input he is giving to the control! Side note: the following code for unminimizing OSK window worked perfectly:
if(osk_wnd->IsIconic())
osk_wnd->PostMessage(WM_SYSCOMMAND, SC_RESTORE, NULL);
Even trying to move that window with this AutoIt script did nothing:
If WinActivate("[CLASS:OSKMainClass]") Then
If WinWaitActive("[CLASS:OSKMainClass]") Then
ConsoleWrite("activ" & @CRLF)
Sleep(500)
If WinMove("[CLASS:OSKMainClass]", "", 30 ,320,360,123) Then
ConsoleWrite("move 1" & @CRLF)
EndIf
EndIf
EndIf
If WinMove("[CLASS:OSKMainClass]", "", 30 ,320,360,123) Then
ConsoleWrite("move 2" & @CRLF)
EndIf
I see the text
activ
move 1
move 2
being printed, but the OSK window is not being moved to anywhere. Maybe it is actively rejecting posiotioning instructions.
I tried this AutoIt script to move the Tabtip.exe Window and it also fails. I tried this script to move the Visual Studio Command Prompt's Window and it moves! GRRRRR!
UPDATE 3: Seems to me this thing has to do with User Access Control and Permissions. If I disable User Access Control or run the application as Administrator the MoveWindow instruction works perfectly! The same applies to AutoIt trying to move OSKMainCLASS window! So, is there some Local or group policy in Windows 7 that allow me to make an exception to the OSK application?
4) For getting the osk.exe running on 64 bit operating system I tried everything that didn't force to disable the SysWOW64 redirection, but I could not escape from it. Till now, I did not see any problems, but maybe the following code will cause problems in the future.
const int sysDirNameSize= 1024;
TCHAR sysDir[sysDirNameSize];
if( !GetSystemDirectory( sysDir, sysDirNameSize) )
{
ASSERT(FALSE);
return;
}
CString osk_path = CString(sysDir) + _T("\\osk.exe");
PVOID pOldValue = NULL;
BOOL bRes= Wow64DisableWow64FsRedirection(&pOldValue);
::ShellExecute(NULL, NULL, osk_path, _T("") , sysDir, SW_SHOW);
if(bRes)
Wow64RevertWow64FsRedirection(pOldValue);
UPDATE 5: Seems last times I tried to execute osk.exe the process begins, but its window doesn't appear! To attribute the value to osk_wnd, I have a function that traverses all GW_CHILD windows of the CWnd::GetDesktopWindow() to search the one which GetClassName(...) is "OSKMainClass" and none is found!
One more time, I solved the problem by myself :)
1) After reading http://social.msdn.microsoft.com/Forums/br/windowsaccessibilityandautomation/thread/aee0be4d-2cf5-45e7-8406-2de3e5d0af03 and http://www.c-plusplus.de/forum/285011-full (German, but Google translator can help), I decided to put the code related on a separate thread. No more hanging when opening CFileDialog windows :)
2) Project manager said that this is a minor problem :)
3) After saying to Project manager that it would be needded to pass a security token when executing osk.exe, he replied that that would introduce much complexity in the code for a very simple thing, and it is preferable that application can run in admin mode :)
4) Not causing problems till now, so let it be :)
Anyway, thanks for help.
For Moving OSK window. initially set low integrity to osk screen by command prompt. then you use movewindow function. it ill work.