Envoyer des touches avec un module Yoctopuce

Envoyer des touches avec un module Yoctopuce

La manière la plus efficace pour utiliser nos modules consiste à utiliser notre librairie, disponible pour les principaux langages de programmation. Mais moyennant un peu de ruse, il est aussi possible d'utiliser nos capteurs pour interfacer des applications existantes dont on ne dispose pas du code source, à l'aide de commandes clavier émulées. Que vous cherchiez à construire un cockpit de simulateur de vol ou à améliorer une interface de saisie un peu ringarde, c'est une piste à suivre....


Principe

L'idée n'est pas très compliquée: on lance en tâche de fond un petit programme qui lit l'état de capteurs Yoctopuce, et en fonction de la valeur lue (et du contexte) envoie une séquence de touches à l'application principale.

La clé du succès consiste à utiliser une séquence de touches fiable pour passer l'information. Par exemple, si vous voulez entrer automatiquement une température mesurée par un Yocto-PT100 dans un formulaire, il faut commencer la séquence par des touches assurant que la température est toujours tapée dans le bon champs. De manière similaire, pour utiliser un bouton rotatif connecté à un Yocto-Knob à la place de touches haut/bas, on assure la fiabilité en traitant explicitement les positions min/max du bouton (pour éviter une éventuelle dérive).

Réalisation

L'émulation de touches clavier est très dépendante du système d'exploitation. Nous allons ici utiliser Windows, puisque c'est encore le système le plus répandu.

Sous Windows, l'émulation de touches au clavier ne peut pas se faire par un service, car les services ne sont pas liés à une session utilisateur. Par contre, on peut émuler des touches depuis une application tournant en tâche de fond, et ayant pour seule interface une icône dans la barre des tâches en bas à droite. Cette application peut être lancée automatiquement dans le menu démarrer par exemple.

Nous allons réaliser cet exemple en C#, et combiner simplement des composants disponibles sur le net:

La seule partie à créer est la "logique" qui lie les capteurs aux touches émulées. La logique étant très dépendante de l'application finale, nous n'allons pas pouvoir la faire pour vous. Mais pour vous mettre le pied à l'étrier, voici deux exemples utilisables pour un cockpit de simulateur de vol.

Deux exemples de logique

Pour être simple et robuste, nous avons codé la logique entièrement par callback.

Pour commencer par le plus simple, voici comment utiliser une entrée du Yocto-Knob (dont la valeur signalée par le callback est un nombre entre 0 et 1000) pour contrôler les freins sur le simulateur de vol X-Plane. On utilise la séquence Ctrl-B pour mettre les freins, et la touche B pour les enlever lorsqu'ils sont mis. L'état courant est gardé dans une variable currBreaks:

static void YBreaksCallback(YAnButton b, string value)
{
  int newBreaks = Convert.ToInt32(value) / 501;

  if (newBreaks == 1 && currBreaks != 1) {
    sim.Keyboard.KeyDown(VirtualKeyCode.LCONTROL);
    sim.Keyboard.KeyPress(VirtualKeyCode.VK_B);
    sim.Keyboard.KeyUp(VirtualKeyCode.LCONTROL);
    currBreaks = 1;
  }
  if (newBreaks == 0 && currBreaks != 0) {
    sim.Keyboard.KeyPress(VirtualKeyCode.VK_B);
    currBreaks = 0;
  }
}



Voici un cas un peu plus complexe, la gestion des gaz dans le même simulateur de vol à l'aide d'un potentiomètre. Il n'existe pas de touche pour choisir une valeur précise, mais seulement deux touches (F1 et F2) pour diminuer et augmenter les gaz. L'amplitude du changement dépend de la durée pendant laquelle la touche est pressée, il est donc important de gérer les fins de course pour éviter que la commande ne dérive.

static void YThrottleCallback(YAnButton b, string value)
{
  int newThrottle = Convert.ToInt32(value) * throttleSteps / 1001;
  int delta = newThrottle - currThrottle;

  if (delta > 0) {
    if (newThrottle >= throttleSteps-1) {
      // min throttle, add extra steps to be sure
      delta += throttleSteps / 4;
    }
    sim.Keyboard.KeyDown(VK_MoreThrottle);
    sim.Keyboard.Sleep(30 * delta);
    sim.Keyboard.KeyUp(VK_MoreThrottle);
  }
  else if (delta < 0) {
    delta = -delta;
    if (newThrottle == 0) {
      // min throttle, add extra steps to be sure
      delta += throttleSteps / 4;
    }
    sim.Keyboard.KeyDown(VK_LessThrottle);
    sim.Keyboard.Sleep(30 * delta);
    sim.Keyboard.KeyUp(VK_LessThrottle);
  }
  currThrottle = newThrottle;
}



Vous trouverez le projet complet pour VisualStudio Express 2012 qui réalise ces fonctions, avec un exemple supplémentaire permettant d'utiliser un Yocto-3D pour émuler les flèches du clavier pour un jeu flash par exemple.

Pour aller plus loin

Si vous désirez automatiser des interactions contextuelles avec une application (par exemple pour de la saisie de mesures), vous améliorerez la fiabilité en utilisant les classes de System.Windows.Automation, qui permettent en particulier de détecter l'application et le champ où se trouve le focus, et de le changer. Il est ainsi possible de faire une Tray App qui pré-rempli un champ de saisie au moment où l'utilisateur y met le focus, sans risquer d'entraver de quelque autre manière la navigation manuelle dans l'application. Pour illustrer l'utilisation de ces classes, voici un autre exemple qui ajoute automatiquement à une fenêtre Notepad chaque nouvelle valeur signalée par un capteur Yoctopuce, et ceci quelle que soit l'application active.

static void SensorCallback(YSensor s, string value)
{
    AutomationElement notepad, textarea;    
    notepad = AutomationElement.RootElement.FindFirst(TreeScope.Children,
        new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));
    if (notepad == null) return;
    textarea = notepad.FindFirst(TreeScope.Descendants,
        new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"));
    if (textarea == null) return;
    try {
        // Save current focus position
        AutomationElement savedFocus = AutomationElement.FocusedElement;
        // Set focus to notepad
        textarea.SetFocus();
        Thread.Sleep(20);
        // Add text using Windows method (works well for standard applications)
        SendKeys.SendWait("^{END}"+s.get_hardwareId()+"="+value+"{Enter}");
        Thread.Sleep(20);
        // Restore focus
        savedFocus.SetFocus();
    } catch (Exception e) { };
}



Et voilà le résultat:

  

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.