Подтвердить что ты не робот

Как управлять панелью ввода текста программно (TabTip.exe) в Windows Vista/7

Я адаптирую приложение для интерфейса сенсорного экрана, и мы хотим использовать панель ввода текста планшета, включенную в Windows Vista/7, в частности ее клавиатуру. Я хочу показать и скрыть его в соответствии с моим приложением. В основном я хочу функции ShowKeyboard() и HideKeyboard(). Какой лучший способ контролировать это?

Я просмотрел API ITextInputPanel, но мне не удалось напрямую управлять клавиатурой (возможно, я что-то пропустил?). Я также безуспешно пытался отправить оконные сообщения в его окно.

Приложение написано на С++/MFC.

Приветствуются любые указатели.

4b9b3361

Ответ 1

Я решил проблему. Оказывается, Spy ++ на самом деле является лучшим другом Windows-программистов.

Во-первых, класс окна окна панели ввода оказывается "IPTip_Main_Window". Я использую это, чтобы получить дескриптор окна так:

HWND wKB = ::FindWindow(_TEXT("IPTip_Main_Window"), NULL);

Оказывается, я могу просто отправить те же сообщения WM_COMMAND, что и его собственное меню. Большинство операций доступны из меню: док-станция, док-станция и плавающий. Код для отправки этих сообщений:

::PostMessage(wKB, WM_COMMAND, MAKEWPARAM(X,0) , 0);

где X - 10021 для док-дна, 10023 для док-станции и 10020 для плавания. 0 в верхнем слове означает, что сообщение отправляется из меню.

Наконец, я хотел показать и скрыть панель ввода. Я заметил, что могу включить настольную полосу, которая включает только одну кнопку для переключения видимости панели ввода. Spy ++ ing на сообщениях, отправленных с этой кнопки, показал, что он отправляет глобальное зарегистрированное оконное сообщение с именем "TabletInputPanelDeskBandClicked". Отправка этого сообщения на панель ввода приводит к переключению его видимости.

Теперь функция HideKeyboard() выглядит так:

DWORD WM_DESKBAND_CLICKED =
    ::RegisterWindowMessage(_TEXT("TabletInputPanelDeskBandClicked"));

void HideKeyboard()
{
    HWND wKB = ::FindWindow(_TEXT("IPTip_Main_Window"), NULL);
    if(wKB != NULL && ::IsWindowVisible(wKB))
    {
        ::PostMessage(wKB, WM_DESKBAND_CLICKED, 0, 0);
    }
}

Функция ShowWindow() реализована аналогично, но она также запустит клавиатуру, если она не запущена.

Обновление:

Похоже, что этот обмен между процессами не разрешен в Windows Vista/7. При запуске этой команды в не-поднятом процессе она будет терпеть неудачу с "доступом отказано". Я предполагаю, что это вызвано защитой процесса пользовательского интерфейса (UIPI), обнаруженной в Windows Vista/7. Поскольку панель ввода планшетного ПК работает как дочерний процесс службы, она имеет более высокий уровень целостности, чем пользовательские программы, и поэтому не может быть отправлена ​​ни один (или очень ограниченный набор) сообщений.

Обновление:

Оказывается, что панель ввода планшетных ПК действительно работает на высоком уровне целостности, тогда как процессы, запущенные ограниченной учетной записью пользователя, являются уровнем целостности среды.

Ответ 2

Для Windows 8:

Примечание. Как и решение для Windows 7, для этого требуется повышенный процесс.

Панель ввода не является потомком HWND_DESKTOP. (Это, вероятно, какое-то окно метро.) Чтобы получить дескриптор окна, выполните серию горизонтальных разверток в сетчатом шаблоне с помощью WindowFromPoint(). Для каждого теста проверьте класс окна родительского окна, чтобы узнать, является ли он "IPTip_Main_Window".

Чтобы отобразить панель ввода, запустите "C:\\Program Files\\Common Files\\microsoft shared\\ink\\tabtip.exe". Чтобы определить, находится ли он уже в режиме стыковки, прочитайте раздел реестра:

HKEY_CURRENT_USER\Software\Microsoft\TabletTip\1.7\EdgeTargetDockedState

Значение 0 указывает, что панель ввода находится в плавающем режиме. Если это так, отправьте следующее сообщение для переключения состояния стыковки:

DWORD WM_DOCK_BUTTON_PRESSED = ::RegisterWindowMessage(_TEXT("IPTipDockButtonPressed"));
PostMessage(hwndInputPanel, WM_DOCK_BUTTON_PRESSED, 0, 0);

Чтобы скрыть клавиатуру, опубликуйте следующее:

PostMessage(hwndInputPanel, WM_SYSCOMMAND, SC_CLOSE, 0);