Я хочу сделать концептуально простую вещь: для каждого элемента управления, который принимает ввод с клавиатуры (CEdit, CCombobox с редактируемым текстом и т. Д.), Когда элемент управления сфокусирован и включен, заставьте появиться экранную клавиатуру. Желательно с поддержкой специальных возможностей (я кое-что читал об автоматизации пользовательского интерфейса Microsoft), а не напрямую вызывать утилиту osk.exe.
Вещь очень похожа на смартфоны с сенсорным экраном, когда пользователь делает акцент на редактируемом элементе управления.
ОБНОВЛЕНИЕ: если есть опция Windows, которая может заставить экранную клавиатуру вести себя так, как я описываю, это прекрасно!
ОБНОВЛЕНИЕ 2: То, что я хочу, похоже на http://msdn.microsoft.com/en-us/library/windows/apps/hh465404.aspx, но в Windows 7.
Я проводил эксперименты с классом IUIAutomation, вызывая непосредственно osk.exe при фокусировке редактируемого элемента управления и закрывая это окно при фокусировке нередактируемого элемента.
Но у меня все еще есть три проблемы:
1) При открытии CFileDialog перестает отвечать на запросы. То же самое происходит только с другим модальным диалогом приложения (в каждом другом модальном диалоге все работает нормально). Я обнаружил, что CFileDialog открывает некоторые фоновые потоки, а также мой единственный проблемный модальный файл. Я подозреваю, что это связано с проблемами потоковой передачи.
2) Когда какой-либо другой элемент управления находится в фокусе, и после этого я нажимаю кнопку DropDown в поле со списком CBS_DROPDOWN, не выбирая его элемент управления редактированием, я вижу, как появляется и исчезает мигание OSK. Используя Spy ++ и UIA Inspect, у меня возникло подозрение, что редактирование текста сфокусировано до того, как поле со списком перейдет в состояние сброса.
3) После экспериментов с 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);
а также некоторые эксперименты по обработке сообщений, например
//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));
Я не мог переместить окно OSK. Важно, что я могу его переместить; в противном случае он будет закрывать сфокусированный элемент управления, и пользователь не сможет увидеть ввод, который он передает элементу управления! Боковое примечание: следующий код для отмены минимизации окна OSK работал отлично:
if(osk_wnd->IsIconic())
osk_wnd->PostMessage(WM_SYSCOMMAND, SC_RESTORE, NULL);
Даже попытка переместить это окно с помощью этого скрипта AutoIt ничего не дала:
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
Я вижу текст
актив
ход 1
ход 2
печатается, но окно OSK никуда не перемещается. Возможно, он активно отвергает инструкции по размещению.
Я пробовал этот скрипт AutoIt для перемещения окна Tabtip.exe, но он тоже не работает. Я пробовал этот сценарий для перемещения окна командной строки Visual Studio, и оно перемещается! ГРРРРР!
ОБНОВЛЕНИЕ 3: Мне кажется, это связано с контролем доступа и разрешениями пользователей. Если я отключу контроль доступа пользователей или запустил приложение от имени администратора, инструкция MoveWindow будет работать отлично! То же самое относится к AutoIt, пытающемуся переместить окно OSKMainCLASS! Итак, есть ли в Windows 7 какая-то локальная или групповая политика, которая позволяет мне сделать исключение для приложения OSK?
4) Для запуска osk.exe в 64-битной операционной системе я пробовал все, что не заставляло отключать перенаправление SysWOW64, но мне не удалось от него уйти. До сих пор я не видел никаких проблем, но, возможно, следующий код вызовет проблемы в будущем.
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);
ОБНОВЛЕНИЕ 5: Кажется, в прошлый раз, когда я пытался запустить osk.exe, процесс начинается, но его окно не появляется! Чтобы присвоить значение osk_wnd, у меня есть функция, которая просматривает все окна GW_CHILD в CWnd :: GetDesktopWindow () для поиска того, у которого GetClassName (...) является "OSKMainClass", и ничего не найдено!