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

Автоматическая всплывающая клавиатура с сенсорным экраном на вкладке ввода 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.

4b9b3361

Ответ 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)

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