web-dev-qa-db-fra.com

Ouvrir automatiquement le clavier tactile de la tablette sur le focus d'entrée WinForms

Lorsque j'exécute une application WinForms (ou Delphi, voir à la fin) sur Windows 10 dans un mode tablette , un clavier tactile n'apparaît pas automatiquement, lorsqu'une zone de saisie est focalisée.

Je crois que cela devrait se produire automatiquement, sans code/configuration supplémentaire.


Pour un test, j'ai l'application de bureau WinForms VS 2015 la plus simple avec un seul TextBox control .

enter image description here

Il s'agit simplement du projet C # Windows Forms Application par défaut tel que créé par Visual Studio. Aucun code ajouté, aucune propriété modifiée. Juste le TextBox a été ajouté, en tombant de la Boîte à outils (encore une fois aucune propriété n'a changé):

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;

Pour vérifier mon hypothèse selon laquelle la fenêtre contextuelle devrait être automatique:

  • J'ai essayé d'exécuter Windows XP version de notepad.exe sous Windows 10. Il fait automatiquement apparaître le clavier tactile. Je doute que Windows XP avait un support explicite pour les claviers tactiles.

  • J'ai également essayé quelques anciennes applications MFC (par exemple FileZilla 2.2.15 de 2005). Il fait également apparaître le clavier tactile sur toutes ses zones de saisie. Encore une fois, je suis presque sûr que le MFC n'avait pas non plus de support explicite pour les claviers tactiles.

  • De même pour les applications basées sur wxWidgets (par exemple FileZilla 3.x).


Il semble qu'il y ait quelque chose de cassé dans WinForms qui empêche le popup automatique. Fait intéressant, la fenêtre contextuelle automatique fonctionne:

  • pour les zones de liste déroulante (modifiables) (ComboBox avec DropDownStyle = DropDown)
  • pour les zones de texte en mode mot de passe ( TextBox.PasswordChar )
  • pour les zones de texte enrichi (RichTextBox)
  • lorsque la zone de saisie est focalisée au moment où le clavier matériel est "retiré" (je teste cela en retournant l'écran sur le portable Lenovo Yoga), mais jamais après.

J'ai vu toutes les astuces concernant une fenêtre contextuelle explicite en exécutant le TabTip.exe. Par exemple.:

La plupart des "solutions" proposent un code comme celui-ci:

var progFiles = @"C:\Program Files\Common Files\Microsoft Shared\ink";
var keyboardPath = Path.Combine(progFiles, "TabTip.exe");
this.keyboardProc = Process.Start(keyboardPath);

Mais je ne peux pas croire que cela puisse être la voie "officielle". Si pour rien d'autre, alors parce qu'il n'y a pas de moyen propre de cacher le clavier ouvert en exécutant le TabTip.exe (les solutions incluent des hacks comme tuer le processus ou envoyer Esc clé).

Et en fait, le hack ci-dessus ne semble plus fonctionner dans la mise à jour anniversaire de Windows 10:


Fait intéressant, je vois le même comportement avec les applications Delphi/C++ Builder/VCL. Le clavier ne s'affiche pas pour les zones d'édition ( TEdit ). Il apparaît pour les zones de liste déroulante ( TComboBox ) et pour les zones d'édition en mode mot de passe ( PasswordChar ). Fait intéressant, pas pour TRichEdit , quelle est la différence notable avec .NET RichTextBox, qui mérite peut-être d'être étudiée.

Cette question (sans réponse) décrit un comportement identique:
L'application écrite Delphi XE8 touch dans le clavier des zones d'édition n'apparaît pas dans Windows 1 .

37
Martin Prikryl

Comme l'indique réponse d'Ofek Shilon , il semble que le clavier tactile puisse tirer parti de I automation .


On peut utiliser l'implémentation de l'automatisation de l'interface utilisateur à partir de UIAutomationClient.dll.

Pour que l'automatisation de l'interface utilisateur soit injectée comme par magie dans une application, l'initialiseur de classe de la classe interne Assembly UiaCoreApi doit être déclenché.

On peut y parvenir par exemple en appelant apparemment no-op:

AutomationElement.FromHandle(IntPtr)(-1)

Une autre façon consiste à implémenter explicitement l'interface utilisateur d'automatisation. Pour cela, implémentez les interfaces ITextProvider / IValueProvider pour le contrôle d'entrée respectif.

Pour lier l'implémentation des interfaces au contrôle, gérez WM_GETOBJECT message de fenêtre avec lParam = RootObjectId.

Pour un exemple d'implémentation, voir


Bien qu'intéressant, les contrôles, pour lesquels le clavier tactile fonctionne immédiatement (comme la zone de liste modifiable ou la zone d'édition de mot de passe, voir la réponse), n'implémentent pas le WM_GETOBJECT/RootObjectId. Il doit y avoir un mécanisme différent derrière eux.

0
Martin Prikryl

La cause première semble être que le textBox de Winforms n'est pas un AutomationElement, alors que les autres contrôles mentionnés (ComboBoxes, etc.) le sont.

Citant Markus von und zu Heber réponse acceptée ici :

Nous l'avons trouvé dans l'article " Clavier tactile automatique pour les TextBoxes dans les applications WPF sur Windows 8 + ", mais cela fonctionne également très bien (et encore plus facilement!) Pour les Winforms. Merci, Dmitry Lyalin!

  1. Insérez une référence à UIAutomationClient.dll dans votre projet

  2. Dans le gestionnaire de chargement de formulaire de la fenêtre principale de l'application, insérez le code suivant:

    var asForm = System.Windows.Automation.AutomationElement.FromHandle(this.Handle);
    
9
Ofek Shilon

J'ai emprunté cette voie à quelques reprises et je n'ai pu mettre en œuvre que taptip.exe option. Et à son tour, fermez la fenêtre en tuant le processus. J'ai également découvert qu'avec certains hacks de registre, vous pouvez obtenir le clavier par défaut dans le panneau d'écriture si vous le souhaitez. Mais cela ne fonctionne que dans Win8 et échoue dans Win10. Voici ce que j'ai fait au cas où quelqu'un d'autre trouverait cela utile:

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");

Je dois donner du crédit à ce message pour l'idée de registre: Application de bureau Windows 8: Ouvrez tabtip.exe sur le clavier secondaire (pour la zone de texte numérique)

8
jaredbaszler

Pour autant que je sache, le lancement de osk.exe ou tabtip.exe est à peu près la façon "standard" de faire fonctionner cela. Je n'ai jusqu'à présent trouvé aucune solution "officielle".

Cependant, si c'était moi qui faisais cela, je ne tuerais pas le processus ou n'enverrais pas de touches pour essayer de fermer le clavier. Au lieu de cela, vous pouvez obtenir le descripteur de fenêtre lorsque vous lancez le processus et l'utiliser pour réduire la fenêtre et la masquer dans la barre des tâches.

Quelqu'un ici a obtenu la poignée de la fenêtre juste pour la fermer, mais cela vous donne l'idée: Afficher et masquer le clavier à l'écran de Windows 8 à partir de WPF

Si vous en avez besoin, faites-le moi savoir et je verrai si je peux trouver le temps de faire un exemple complet.

5
James Decker

Utilisez un RichTextBox au lieu d'un contrôle TextBox. La RichTextBox prend en charge le clavier tactile et affiche automatiquement le clavier lorsque la mise au point est gagnée. (similaire à d'autres contrôles d'entrée tels que la zone de liste déroulante)

Le RichTextBox prend également en charge les mêmes propriétés que le TextBox, il devrait donc y avoir une baisse de changement dans la plupart des cas. (Les deux contrôles dérivent de TextBoxBase)

J'ai remarqué que si le clavier tactile a été supprimé après son apparition, vous devrez peut-être appuyer deux fois sur le contrôle pour le faire revenir.

1
Rob Karmes