Автоматическая всплывающая клавиатура с сенсорным экраном на вкладке ввода WinForms
Когда я запускаю приложение WinForms (или Delphi, см. в конце) в Windows 10 в режиме планшета, сенсорная клавиатура не появляется автоматически, когда фокус ввода находится в фокусе.
Я считаю, что это должно происходить автоматически, без какого-либо дополнительного кода/настройки.
Для теста у меня самое простое настольное приложение VS 2015 WinForms с одним TextBox
элементом управления.
![enter image description here]()
Это просто проект С# приложения Windows Forms по умолчанию, созданный Visual Studio. Код не добавлен, свойства не изменены. Просто TextBox
был добавлен путем удаления из панели инструментов (опять же, свойства не изменились):
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox1.Location = new System.Drawing.Point(64, 27);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
this.textBox1.TabIndex = 0;
Чтобы проверить мое предположение, что всплывающее окно должно быть автоматическим:
Я пытался запустить версию notepad.exe
для Windows XP на Windows 10. Она автоматически выдает сенсорную клавиатуру. Я сомневаюсь, что в Windows XP была какая-то явная поддержка сенсорных клавиатур.
Я также попробовал некоторые древние приложения MFC (например, FileZilla 2.2.15 от 2005 года). Он также выскакивает сенсорную клавиатуру на всех своих полях ввода. Опять же, я почти уверен, что в MFC также не было явной поддержки сенсорных клавиатур.
То же самое для приложений, построенных на wxWidgets (например, FileZilla 3.x).
Похоже, что в WinForms что-то сломалось, что мешает автоматическому всплывающему окну. Интересно, что автоматическое всплывающее окно работает:
- для (редактируемых) полей со списком (
ComboBox
с DropDownStyle = DropDown
)
- для текстовых полей в режиме пароля (
TextBox.PasswordChar
)
- для расширенных текстовых полей (
RichTextBox
)
- когда поле ввода находится в фокусе в тот момент, когда аппаратная клавиатура "удалена" (я проверяю это, переворачивая экран на ноутбуке Lenovo Yoga), но не после.
Я видел все подсказки о явном всплывающем окне, запустив TabTip.exe
. Например.:
Большинство "решений" предлагают такой код:
var progFiles = @"C:\Program Files\Common Files\Microsoft Shared\ink";
var keyboardPath = Path.Combine(progFiles, "TabTip.exe");
this.keyboardProc = Process.Start(keyboardPath);
Но я не могу поверить, что это может быть "официальным" способом. Хотя бы потому, что нет чистого способа скрыть открытую клавиатуру, запустив TabTip.exe
(решения включают в себя такие хаки, как уничтожение процесса или отправка клавиши Esc).
И на самом деле вышеупомянутый хак больше не работает в Windows 10 Anniversary Update:
Интересно, что я вижу такое же поведение с приложениями Delphi/C++ Builder/VCL. Клавиатура не открывается для полей редактирования (TEdit
). Он появляется для полей со списком (TComboBox
) и для полей редактирования в режиме пароля (PasswordChar
). Интересно не для TRichEdit
, в чем заметное отличие от .NET RichTextBox
, которое, возможно, стоит исследовать.
Этот (без ответа) вопрос описывает идентичное поведение:
Приложение, написанное Delphi XE8 touch, в полях редактирования клавиатуры не отображается в Windows 10.
Ответы
Ответ 1
Как подсказал ответ офека Шилона, похоже, что сенсорная клавиатура может использовать автоматизацию пользовательского интерфейса.
Можно использовать реализацию автоматизации пользовательского интерфейса из UIAutomationClient.dll
.
Для того чтобы автоматизация пользовательского интерфейса была волшебным образом внедрена в приложение, должен быть запущен инициализатор класса внутреннего класса сборки UiaCoreApi
.
Это можно сделать, например, вызвав кажущееся бездействие:
AutomationElement.FromHandle(IntPtr)(-1)
Другой способ - реализовать интерфейс автоматизации в явном виде. Для этого реализуем ITextProvider
/IValueProvider
интерфейсы для соответствующего управления вводом.
Чтобы привязать реализацию интерфейсов к элементу управления, обработайте сообщение окна WM_GETOBJECT
с помощью lParam
= RootObjectId
.
Пример реализации см. в
Интересно, что элементы управления, для которых сенсорная клавиатура работает "из коробки" (например, поле со списком или окно редактирования пароля, см. ответ), не реализуют WM_GETOBJECT
/RootObjectId
. За ними должен быть другой механизм.
Ответ 2
Я несколько раз ездил по этой дороге и только когда-либо мог реализовать опцию taptip.exe
. И, в свою очередь, закройте окно, убив процесс. Я также узнал, что с некоторыми хаками реестра вы можете получить клавиатуру по умолчанию для панели рукописного ввода, если вы этого захотите. Но тогда это работает только в Win8 и терпит неудачу в Win10. Вот что я сделал в случае, если кто-то еще найдет это полезным:
RegistryKey registryKey = Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\TabletTip\\1.7");
registryKey?.SetValue("KeyboardLayoutPreference", 0, RegistryValueKind.DWord);
registryKey?.SetValue("LastUsedModalityWasHandwriting", 1, RegistryValueKind.DWord);
Process.Start(@"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe");
Мне нужно отдать должное этому сообщению за идею реестра: Windows 8 Desktop App: Открыть tabtip.exe на вторичной клавиатуре (для числового текстового поля)
Ответ 3
Основная причина, по-видимому, в том, что текстовый блок Winforms не является элементом AutomationElement, а остальные элементы управления (ComboBoxes и т.д.).
Цитирование Markus von und zu Heber принятый ответ здесь:
Мы нашли это в статье " Автоматическая сенсорная клавиатура для текстовых полей в Приложения WPF в Windows 8+", но он также работает очень хорошо (и даже проще!) для winforms. Спасибо, Дмитрий Лялин!
-
Вставьте ссылку на UIAutomationClient.dll в свой проект
-
В обработчике формы-приложения главного окна приложения вставьте следующий код:
var asForm = System.Windows.Automation.AutomationElement.FromHandle(this.Handle);
Ответ 4
Насколько я могу судить, запуск osk.exe
или tabtip.exe
в значительной степени является "стандартным" способом выполнения этой работы. До сих пор я не нашел "официального" решения.
Однако, если бы я это делал, я бы не стал убивать процесс или отправлять ключи, чтобы попытаться убрать клавиатуру. Вместо этого вы можете получить дескриптор окна при запуске процесса и использовать его для минимизации окна и скрыть его из панели задач.
Кто-то здесь получил дескриптор окна, чтобы закрыть его, но он дает вам идею: Показывать и скрывать Windows 8 на экранной клавиатуре из WPF
Если вам нужно, дайте мне знать, и я посмотрю, смогу ли я найти время, чтобы сделать полный пример.
Ответ 5
Используйте RichTextBox вместо элемента управления TextBox. RichTextBox поддерживает сенсорную клавиатуру и автоматически всплывает на клавиатуре при достижении фокуса. (аналогично другим элементам управления ввода, например, поле со списком)
RichTextBox также поддерживает те же свойства, что и TextBox, поэтому в большинстве случаев это должно быть снижение. (Оба элемента управления получают из TextBoxBase)
Я заметил, что если сенсорная клавиатура была уволена после того, как она всплывает, вам может потребоваться дважды нажать на элемент управления, чтобы заставить его вернуться назад.