Pull to refresh
0

Один из способов адаптации настольных приложений под сенсорный экран

Reading time 3 min
Views 13K
Поработав некоторое время с Windows 8 на планшете и ультрабуке с сенсорным экраном, я столкнулся с одной интересной особенностью. При работе с полями ввода в настольных (desktop) приложениях экранная клавиатура не появляется автоматически, приходится каждый раз вызывать путем касания значка в системном лотке, а потом закрывать нажатием на кнопку закрытия окна.
В Windows UI приложениях такой проблемы нет, клавиатура автоматически появляется, как только поле ввода получает фокус и исчезает, когда в ней отпадает необходимость — например, элемент управления потерял фокус ввода, либо пользователь начал вводить текст с «железной» клавиатуры.
Так как я не только пользователь, но и разработчик, то подумал: а что если перенести это поведение экранной клавиатуры и в свои настольные приложения? Задача поставлена, ищем решение.
Поздравляю хабрачитателей с приближающимися праздниками! Всем, дочитавшим до конца — готовый к использованию код в подарок! :)

Задача номер 1 — отобразить клавиатуру.


Tablet PC Input Panel — это приложение, входящее в состав стандартной поставки Windows 8, которое, собственно и отображает экранную клавиатуру. Запустим его и посмотрим, что получится. После запуска приложения видим, что на экране появилась клавиатура. Следовательно для отображения клавиатуры реализуем программный запуск.

TCHAR kbdPath[MAX_PATH] = {0};

ExpandEnvironmentStrings(_T("%CommonProgramW6432%"), kbdPath, _countof(kbdPath));
wcscat_s(kbdPath, _countof(kbdPath), _T("\\microsoft shared\\ink\\tabtip.exe"));

ShellExecute(NULL, _T("open"), kbdPath, NULL, NULL, SW_SHOWNORMAL);


Если выполнить этот код на экране появится экранная клавиатура, то чего и добивались.

Задача номер 2 — скрыть клавиатуру


После того как пользователь нажал Enter или поле ввода потеряло фокус неплохо было бы скрыть клавиатуру, чтобы ему не пришлось делать это самостоятельно. Сделать это еще проще, так как клавиатура отображается в окне то реализовать это можно путем программного закрытия или сворачивания окна. Но для начала его необходимо как-то найти.

Я запустил клавиатуру и проверил свойства окна с помощью утилиты Spy++, входящей в состав Visual Studio и нашел то, что меня интересовало, а именно класс окна IPTip_Main_Window. Остальное дело техники, используя имя класса находим окно и сворачиваем его, путем отправки соответствующего сообщения.

HWND kbd = ::FindWindow(_T("IPTip_Main_Window"), NULL);

if(kbd != NULL)
{
	::PostMessage(kbd, WM_SYSCOMMAND, SC_CLOSE, 0);
}


Задача номер 3 — развернуть во всю ширину экрана, свернуть клавиатуру


Экранная клавиатура может иметь на экране стандартный размер, а может быть развернута во всю ширину экрана. Для изменения ширины клавиатуры можно отправить ей сообщение, которое она получает при нажатии на кнопку разворачивания окна, находящуюся в верхнем левом углу.

DWORD msgSwitchTo = ::RegisterWindowMessage(_T("IPTipDockButtonPressed"));

HWND kbd = ::FindWindow(_T("IPTip_Main_Window"), NULL);

if(kbd != NULL)
{
	::PostMessage(kbd, msgSwitchTo, 0x891, 0);
}

Также не плохо было бы понимать, в каком состоянии находится клавиатура. Здесь я решил поступить просто — определить ширину экрана, далее ширину клавиатуры и сравнить два этих значения

HWND kbd = ::FindWindow(_T("IPTip_Main_Window"), NULL);

int screenWidth = GetSystemMetrics(SM_CXSCREEN);

RECT touchWindow = {0};

if(GetWindowRect(kbd, &touchWindow) == false)
{
	return false;
}

int touchWidth = touchWindow.right - touchWindow.left;

return (screenWidth <= touchWidth);

Для простоты использования в своих проектах я обернул все полученные функции в класс CTouchKeyboard

class CTouchKeyboard
{
public:
	static bool IsVisible();
	static bool Show();
	static bool Hide();
	static bool Dock();
	static bool IsDocked();

private:
	static HWND FindKeyboardWindow();
	static bool PostMessageToKeyboard(DWORD msg, WPARAM wParam, LPARAM lParam);
};


Как использовать в приложениях


При работе с текстовыми полями пользователь ожидает, что переходе в поле появится экранная клавиатура. Как это реализовать? При получении фокуса ввода текстовым полем родительское окно получает уведомление EN_SETFOCUS, соответственно добавляем обработчик и в обработчике этого уведомления вызываем

CTouchKeyboard::Show(); 

При потере фокуса ввода родительское окно получает уведомление EN_KILLFOCUS, соответственно там будет вызываться

CTouchKeyboard::Hide();  

Собираем, запускаем, наслаждаемся результатом — если выбрать текcтовое поле клавиатура появляется, нажимаем клавишу Tab — клавиатура исчезает.



Пример использования и исходники доступны здесь.
Tags:
Hubs:
+7
Comments 16
Comments Comments 16

Articles

Information

Website
www.intel.ru
Registered
Founded
Employees
5,001–10,000 employees
Location
США
Representative
Анастасия Казантаева