Apprendre à programmer un clavier virtuel en Qt

Tobias Koenig

Traducteur

David Faure

Dans le tutoriel sur la programmation avec les méthodes de saisie, nous avons appris les concepts généraux des méthodes de saisie dans Qt, et nous avons jeté un coup d'œil en coulisses pour voir comment, dans le système de fenêtres natif, l'évènement associé à l'appui sur une touche circule à travers la pile de saisie de Qt jusqu'à apparaître à l'écran au sein d'un QLineEdit. Dans ce contexte, la méthode de saisie était utilisée pour permettre à l'utilisateur de modifier la saisie (par exemple composer un caractère de langue chinoise à partir d'une saisie Latin1).

Aujourd'hui, nous voulons éclairer un autre cas d'utilisation du système de méthode de saisie, à savoir la mise en œuvre d'un clavier virtuel hors processus qui peut être utilisé pour alimenter en texte saisi, des applications Qt quelconques.

Vous avez la possibilité de réagir sur ce tutoriel, dans le forum.

Commentez

- Titre : Apprendre à programmer un clavier virtuel en Qt

- Auteur : Tobias Koenig

- Traducteur : David Faure

- Parution : 22 mai 2017

- Public visé :

- Licence : Copyright ® 2017 Tobias Koenig. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Voir également :

- Tutoriel pour apprendre à programmer avec les méthodes de saisies en Qt

Sommaire

- I. Pourquoi avons-nous besoin d'un clavier virtuel ?

- II. Comment mettre en œuvre un clavier virtuel avec Qt ?

- III. L'application clavier

- IV. Le plugin Qt Input Method

- V. Réunir tous les éléments

- VI. Améliorations supplémentaires

- VII. Ressources

- Notes de la rédaction Developpez.com

I - Pourquoi avons-nous besoin d'un clavier virtuel ?

Croyez-le ou non, il existe des appareils ne disposant pas du moindre clavier matériel (vous pourriez fort bien en tenir un à l'instant même où vous lisez ces lignes ) : téléphones portables, tablettes, bornes de kiosques, pour ne citer qu'eux. Le clavier virtuel (parfois appelé clavier visuel) est une application s'exécutant en parallèle des autres applications en cours sur l'appareil. Chaque fois que l'utilisateur souhaite saisir du texte à l'intention des autres applications, le clavier virtuel fait apparaître une fenêtre imitant les touches d'un clavier matériel. L'utilisateur peut alors cliquer sur les touches et l'application de clavier virtuel convertit ces clics en évènements clavier, qui seront alors envoyés à la fenêtre d'application correspondant à la zone de saisie active. L'application destinataire traite les évènements comme des évènements clavier ordinaires, de sorte que l'utilisation d'un clavier matériel ou virtuel est totalement transparente pour l'application.

II - Comment mettre en œuvre un clavier virtuel avec Qt ?

Il existe deux manières de mettre en œuvre un clavier virtuel avec Qt : dans le processus et hors processus.

Pour l'approche dans le processus, le clavier virtuel devient simplement un élément QWidget ou QtQuick de plus, qui fait apparaître les touches de clavier, réagit aux interactions utilisateur et transmet les évènements QKeyEvents générés à la boucle d'évènements de l'application. L'avantage de cette approche est qu'elle est très facile à mettre en œuvre, car elle ne nécessite aucune communication interprocessus entre le clavier et l'application. L'inconvénient, toutefois, est que chaque application doit posséder sa propre instance du clavier virtuel, et il peut être nécessaire de synchroniser l'état de toutes ces instances (visibilité, activité) entre applications.

En revanche, l'approche hors processus permet à une unique instance du clavier virtuel d'être partagée entre toutes les autres applications, de sorte qu'aucune synchronisation entre instances multiples du clavier virtuel n'est nécessaire. Cela suppose que vous définissiez un mécanisme de communication interprocessus entre l'instance globale du clavier virtuel et toutes les applications souhaitant l'utiliser.

Dans ce tutoriel, que nous déroulons maintenant, nous allons adopter l'approche hors processus et faire appel à D-Bus comme mécanisme de communication interprocessus : il ne faut que peu de code pour l'intégrer à une application Qt et il a déjà fait ses preuves avec d'autres systèmes de méthodes de saisie (IBus).

III - L'application clavier

Notre application clavier s'appuie sur des widgets Qt afin de minimiser la quantité de code à écrire, mais les concepts sont transposables à une interface utilisateur basée sur QtQuick. L'interface utilisateur réelle est vraiment élémentaire, un simple QGridLayout comportant quelques boutons. Il y a un bouton pour chaque chiffre, un pour chaque caractère latin, ainsi que des touches Retour et Entrée. Par souci de simplicité, nous omettons les touches Majuscules et Verrouillage des Majuscules (et, par conséquent, la possibilité de saisir des caractères majuscules), nous le laissons en exercice au lecteur .

Le code source du fichier main.cpp a l'allure suivante :

1. #include <QApplication>

2. #include <QDBusConnection>

4. #include "keyboard.h"

6. int main(int argc, char **argv)

7. {

8. QApplication app(argc, argv);

10. if (!QDBusConnection::sessionBus().registerService("com.kdab.inputmethod")) {

11. qFatal("Unable to register at DBus");

12. return 1;

13. }

15. Keyboard keyboard;

17. if (!QDBusConnection::sessionBus().registerObject("/VirtualKeyboard", &keyboard, QDBusConnection::ExportAllSignals | QDBusConnection::ExportAllSlots)) {

18. qFatal("Unable to register object at DBus");

19. return 1;

20. }

22. return app.exec();

23. }

Dans les trois premières lignes, nous incluons les fichiers d'en-tête des classes que nous souhaitons utiliser : QApplication pour la boucle d'évènements, QDBusConnection pour rendre cette application accessible à travers D-Bus, et keyboard.h, qui fournit l'interface graphique du clavier. À la ligne 11, nous essayons d'enregistrer notre application dans le bus de session sous le nom unique 'com.kdab.inputmethod'. Si cela échoue, c'est qu'il y a un problème avec D-Bus et il ne sert donc à rien d'exécuter l'application, car elle ne sera pas accessible par d'autres applications. À la ligne 16, nous créons une instance de notre interface de clavier, qui est encapsulée dans la classe Keyboard. Notez que nous n'appelons pas show() sur l'objet Keyboard ici même ; ainsi, au lancement, l'application ne fera pas apparaître de fenêtre. À la ligne 18, nous publions l'objet Keyboard sous le chemin '/VirtualKeyboard' et nous rendons accessibles tous ses slots publics et ses signaux. C'est tout ce qu'il y a à faire dans main.cpp, jetons maintenant un coup d'œil à keyboard.h :

1. class Keyboard : public QWidget

2. {

3. Q_OBJECT

5. public:

6. explicit Keyboard(QWidget *parent = Q_NULLPTR);

8. public slots:

9. void showKeyboard();

10. void hideKeyboard();

11. bool keyboardVisible() const;

13. signals:

14. void specialKeyClicked(int key);

15. void keyClicked(const QString &text);

17. private slots:

18. void buttonClicked(int key);

19. };

Notre classe Keyboard hérite de QWidget et peut donc être affichée comme une fenêtre à l'écran. À l'exception du constructeur, où se fait toute l'initialisation de l'interface utilisateur, elle fournit trois slots publics permettant d'afficher l'interface du clavier, de la cacher, et d'interroger sa visibilité courante. De surcroît, deux signaux nommés keyClicked() et specialKeyClicked() sont émis respectivement lorsque l'utilisateur clique sur un nombre ou une lettre (keyClicked()) ou sur les touches Retour ou Entrée (specialKeyClicked()).

1. Keyboard::Keyboard(QWidget *parent)

2. : QWidget(parent)

3. {

4. setWindowFlags(Qt::WindowDoesNotAcceptFocus | Qt::Tool |

5. Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);

7. QGridLayout *gridLayout = new QGridLayout(this);

9. QSignalMapper *mapper = new QSignalMapper(this);

10. connect(mapper, SIGNAL(mapped(int)), SLOT(buttonClicked(int)));

12. int row = 0;

13. int column = 0;

15. for (int i = 0; i < layoutSize; ++i) {

16. if (keyboardLayout[i].key == NEXT_ROW_MARKER) {

17. row++;

18. column = 0;

19. continue;

20. }

22. QPushButton *button = new QPushButton;

23. button->setFixedWidth(40);

24. button->setText(QString::fromLatin1(keyboardLayout[i].label));

26. mapper->setMapping(button, keyboardLayout[i].key);

27. connect(button, SIGNAL(clicked()), mapper, SLOT(map()));

29. gridLayout->addWidget(button, row, column);

30. column++;

31. }

32. }

Pour s'assurer que l'interaction avec la fenêtre de clavier ne retire pas le focus de la fenêtre d'application utilisant le clavier virtuel, nous devons définir la valeur du drapeau Qt::WindowDoesNotAcceptFocus. À partir de la ligne 8, nous assemblons l'interface en créant l'objet QGridLayout et en y plaçant les boutons des touches du clavier. Pour éviter de dupliquer du code, nous enregistrons les propriétés des touches (code et étiquette de la touche) dans un tableau que nous parcourons dans la boucle for de la ligne 16. Pour chaque élément, nous créons un objet QPushButton de largeur fixe et dont le libellé correspond à l'étiquette de la touche. Comme tous les clics sur les boutons doivent être gérés de manière centralisée, nous utilisons QSignalMapper pour invoquer le slot privé buttonClicked(int key) dès que l'un des objets QPushButton est cliqué. Le paramètre key correspond à l'élément Qt::Key tel qu'il est défini dans le tableau keyboardLayout défini comme suit :

1. #define NEXT_ROW_MARKER 0

3. struct KeyboardLayoutEntry{

4. int key;

5. const char *label;

6. };

8. KeyboardLayoutEntry keyboardLayout[] = {

9. { Qt::Key_1, "1" },

10. { Qt::Key_2, "2" },

11. { Qt::Key_3, "3" },

12. { Qt::Key_4, "4" },

13. { Qt::Key_5, "5" },

14. { Qt::Key_6, "6" },

15. { Qt::Key_7, "7" },

16. { Qt::Key_8, "8" },

17. { Qt::Key_9, "9" },

18. { Qt::Key_0, "0" },

19. { Qt::Key_Backspace, "<-" },

20. { NEXT_ROW_MARKER, 0 },

21. { Qt::Key_Q, "q" },

22. { Qt::Key_W, "w" },

23. ...

24. };

26. const static int layoutSize = (sizeof(keyboardLayout) /

27. sizeof(KeyboardLayoutEntry));

Ainsi, chaque élément comporte le code Qt::Key et l'étiquette à utiliser. De plus, nous avons inséré des marqueurs spéciaux comportant le code de touche 'NEXT_ROW_MARKER' qui garantissent simplement que les boutons suivants seront affichés sur la ligne suivante de notre objet QGridLayout.

Maintenant, que se passe-t-il si l'utilisateur clique sur l'un des objets QPushButtons ? Le slot buttonClicked() est invoqué :

1. void Keyboard::buttonClicked(int key)

2. {

3. if ((key == Qt::Key_Enter) || (key == Qt::Key_Backspace))

4. emit specialKeyClicked(key);

5. else

6. emit keyClicked(keyToCharacter(key));

7. }

Si la touche utilisée est Retour ou Entrée, le signal specialKeyClicked() est émis ; sinon, le code de touche est associé à un caractère et c'est le signal keyClicked() qui est émis, avec ce caractère comme paramètre. Pour effectuer la correspondance, on invoque la méthode d'aide keyToCharacter() qui est définie comme suit :

1. static QString keyToCharacter(int key)

2. {

3. for (int i = 0; i < layoutSize; ++i) {

4. if (keyboardLayout[i].key == key)

5. return QString::fromLatin1(keyboardLayout[i].label);

6. }

8. return QString();

9. }

Dans cette mise en œuvre simple de clavier, nous nous contentons de renvoyer l'étiquette de la touche (un caractère minuscule ou un nombre). Dans une version plus avancée, il faudrait tenir compte de touches de modification éventuellement utilisées pour y associer des touches majuscules et autres caractères spéciaux.

La mise en œuvre des slots publics restants est simple. Ils transmettent simplement les requêtes vers les méthodes correspondantes de la classe de base QWidget.

1. void Keyboard::showKeyboard()

2. {

3. QWidget::show();

4. }

6. void Keyboard::hideKeyboard()

7. {

8. QWidget::hide();

9. }

11. bool Keyboard::keyboardVisible() const

12. {

13. return QWidget::isVisible();

14. }

En résumé  : nous avons maintenant une application d'interface de clavier qui est accessible via D-Bus sous le nom « com.kdab.inputmethod/VirtualKeyboard ». Elle fournit les méthodes requises pour faire apparaître le clavier à l'écran, le cacher, et pour demander son état de visibilité courant. De plus, cette application émet les deux signaux specialKeyClicked() et keyClicked() (également via D-Bus) dès que l'utilisateur clique sur l'un des objets QPushButton.

Un test simple pour savoir si l'interface du clavier fonctionne comme attendu consiste à lancer l'application et à utiliser qdbusviewer pour examiner son interface D-Bus, invoquer les slots exportés et enregistrer les émissions de signaux.

Maintenant que nous disposons du clavier virtuel, nous allons jeter un coup d'œil à la mise en œuvre de la méthode de saisie correspondante…

IV - Le plugin Qt Input Method

Dans le tutoriel précédent relatif à la programmation avec les méthodes de saisies, nous avons appris que la communication entre les composants Qt de saisie de texte et le système de méthode de saisie s'effectue au moyen de la classe frontale publique QInputMethod et la classe interne privée QPlatformInputContext. Si nous souhaitons fournir notre propre méthode de saisie, nous devons faire deux choses :

1. Mettre en œuvre une version personnalisée de la sous-classe QPlatformInputContext ;

2. Mettre en œuvre un objet QPlatformInputContextPlugin fournissant cette sous-classe à Qt.

Commençons par le second point en jetant un coup d'œil au fichier main.cpp du plugin :

1. class QVkImPlatformInputContextPlugin : public QPlatformInputContextPlugin

2. {

3. Q_OBJECT

4. Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface" FILE "vkim.json")

6. public:

7. QVkImPlatformInputContext *create(const QString&, const QStringList&) Q_DECL_OVERRIDE;

8. };

10. QVkImPlatformInputContext *QVkImPlatformInputContextPlugin::create(const QString& system, const QStringList& paramList)

11. {

12. Q_UNUSED(paramList);

14. if (system == QLatin1String("vkim")) {

15. return new QVkImPlatformInputContext;

16. }

18. return 0;

19. }

Nous déclarons une nouvelle classe QVkImPlatformInputContextPlugin héritant de QPlatformInputContextPlugin et nous réimplémentons la méthode virtuelle create(). Les métadonnées du plugin sont stockées dans le fichier externe 'vkim.json' qui contient simplement les lignes suivantes :

1. {

2. "Keys": [ "vkim" ]

3. }

Le terme 'vkim' est une abréviation de 'virtual keyboard input method' (méthode de saisie de clavier virtuel) et sert d'identifiant à notre plugin de méthode de saisie. Nous verrons plus tard où cela est nécessaire.

Dans la mise en œuvre de QVkImPlatformInputContextPlugin::create(), nous testons si l'objet demandé possède cet identifiant et, si c'est le cas, nous renvoyons une nouvelle instance de notre classe personnalisée QVkImPlatformInputContext. QVkImPlatformInputContext est notre réimplémentation personnalisée de QPlatformInputContext avec la déclaration suivante :

1. class QVkImPlatformInputContext : public QPlatformInputContext

2. {

3. Q_OBJECT

5. public:

6. QVkImPlatformInputContext();

7. ~QVkImPlatformInputContext();

9. bool isValid() const Q_DECL_OVERRIDE;

10. void setFocusObject(QObject *object) Q_DECL_OVERRIDE;

12. void showInputPanel() Q_DECL_OVERRIDE;

13. void hideInputPanel() Q_DECL_OVERRIDE;

14. bool isInputPanelVisible() const Q_DECL_OVERRIDE;

16. private slots:

17. void keyboardSpecialKeyClicked(int key);

18. void keyboardKeyClicked(const QString &character);

20. private:

21. QDBusInterface *m_keyboardInterface;

23. QObject *m_focusObject;

24. };

Elle réimplémente cinq méthodes virtuelles de QPlatformInputContext ayant les fonctionnalités suivantes :

- isValid() est appelée par QPlatformInputContextFactory (la classe chargeant le plugin et invoquant la méthode create()) pour vérifier si la méthode de saisie est prête à être utilisée ;

- setFocusObject() est appelée par QGuiApplication pour informer QPlatformInputContext de l'objet qui est actuellement la cible de saisie ;

- showInputPanel() est appelée par QInputMethod::show() pour appeler l'interface du clavier si un champ de saisie de texte devient la cible de saisie ;

- hideInputPanel() est appelée par QInputMethod::hide() pour cacher l'interface du clavier si le champ de saisie de texte n'est plus la cible de saisie ;

- isInputPanelVisible() est appelée par QInputMethod::isVisible() pour informer l'application de l'état de visibilité de l'interface du clavier.

De plus, elle comporte deux slots privés keyboardSpecialKeyClicked() et keyboardKeyClicked() qui sont invoqués dès que nous recevons les signaux correspondants de notre application d'interface de clavier via D-Bus. Les deux variables membres stockent un pointeur vers l'interface D-Bus et un pointeur vers l'objet actuellement cible de saisie dans l'application.

Jetons maintenant un coup d'œil à la mise en œuvre de cette classe, là où toute la magie opère :

1. QVkImPlatformInputContext::QVkImPlatformInputContext()

2. : m_focusObject(0)

3. {

4. m_keyboardInterface = new QDBusInterface("com.kdab.inputmethod",

5. "/VirtualKeyboard",

6. "local.server.Keyboard",

7. QDBusConnection::sessionBus(),

8. this);

10. connect(m_keyboardInterface, SIGNAL(keyClicked(QString)),

11. SLOT(keyboardKeyClicked(QString)));

12. connect(m_keyboardInterface, SIGNAL(specialKeyClicked(int)),

13. SLOT(keyboardSpecialKeyClicked(int)));

14. }

C'est à l'intérieur du constructeur que la connexion avec l'interface D-Bus de l'interface clavier est établie. Nous devons renseigner ici l'identifiant d'application « com.kdab.inputmethod » et faire pointer le chemin « /VirtualKeyboard » vers l'objet Keyboard exporté. Comme notre classe doit être informée des touches sur lesquelles l'utilisateur a cliqué dans l'interface du clavier, nous connectons les deux signaux keyClicked() et specialKeyClicked() aux deux slots privés.

1. bool QVkImPlatformInputContext::isValid() const

2. {

3. return m_keyboardInterface->isValid();

4. }

Au sein de la méthode isValid(), nous renvoyons simplement si l'objet d'interface D-Bus est valide. Si nous ne pouvons pas nous connecter à l'application d'interface de clavier, notre méthode de saisie n'est alors d'aucune utilité : ce test est donc suffisant.

1. void QVkImPlatformInputContext::setFocusObject(QObject *object)

2. {

3. m_focusObject = object;

4. }

Dans le cas où QGuiApplication nous informe d'un nouvel objet devenu cible de saisie, nous stockons dans la variable membre le pointeur vers cet objet, car nous en aurons besoin plus loin (voir ci-dessous).

1. void QVkImPlatformInputContext::showInputPanel()

2. {

3. m_keyboardInterface->call("showKeyboard");

4. }

6. void QVkImPlatformInputContext::hideInputPanel()

7. {

8. m_keyboardInterface->call("hideKeyboard");

9. }

Lorsque QInputMethod::show() ou QInputMethod::hide() sont invoquées par les widgets de saisie de texte (par exemple QLineEdit ou QTextEdit), les méthodes showInputPanel() et hideInputPanel() sont appelées et transmettent ces requêtes à travers l'interface D-Bus vers le processus correspondant à l'interface du clavier :

1. bool QVkImPlatformInputContext::isInputPanelVisible() const

2. {

3. const QDBusReply<bool> reply = m_keyboardInterface->call("keyboardVisible");

5. if (reply.isValid())

6. return reply.value();

7. else

8. return false;

9. }

Nous adoptons la même approche pour QInputMethod::isVisible() qui appelle isInputPanelVisible(). Dans ce cas, nous invoquons également la fonction distante dans le processus d'interface clavier via D-Bus mais, cette fois, nous devons aussi traiter la valeur de retour :

1. void QVkImPlatformInputContext::keyboardKeyClicked(const QString &characters)

2. {

3. if (!m_focusObject)

4. return;

6. QInputMethodEvent event;

7. event.setCommitString(characters);

9. QGuiApplication::sendEvent(m_focusObject, &event);

10. }

Nous arrivons maintenant à la section où notre classe personnalisée QPlatformInputContext redirige vers l'application utilisateur les clics sur les touches tels qu'ils sont reçus de l'application d'interface de clavier. Pour du texte, c'est fait avec QInputMethodEvent. Ainsi, si un widget de saisie de texte est actuellement la cible de saisie (m_focusObject != null), nous définissons les caractères saisis comme commit string dans l'évènement et nous les envoyons à l'objet.

1. void QVkImPlatformInputContext::keyboardSpecialKeyClicked(int key)

2. {

3. if (!m_focusObject)

4. return;

6. if (key == Qt::Key_Enter) {

7. QKeyEvent *pressEvent = new QKeyEvent(QEvent::KeyPress,

8. Qt::Key_Enter,

9. Qt::NoModifier);

11. QGuiApplication::postEvent(m_focusObject, pressEvent);

13. QKeyEvent *releaseEvent = new QKeyEvent(QEvent::KeyRelease,

14. Qt::Key_Enter,

15. Qt::NoModifier);

17. QGuiApplication::postEvent(m_focusObject, releaseEvent);

18. } else if (key == Qt::Key_Backspace) {

19. QKeyEvent *pressEvent = new QKeyEvent(QEvent::KeyPress,

20. Qt::Key_Backspace,

21. Qt::NoModifier);

23. QGuiApplication::postEvent(m_focusObject, pressEvent);

25. QKeyEvent *releaseEvent = new QKeyEvent(QEvent::KeyRelease,

26. Qt::Key_Backspace,

27. Qt::NoModifier);

29. QGuiApplication::postEvent(m_focusObject, releaseEvent);

30. }

31. }

Pour chaque saisie non textuelle (dans notre cas, les touches Retour et Entrée), nous générons des QKeyEvents correspondant aux évènements d'appui et de relâchement de touche, et nous les envoyons à l'objet cible de saisie à travers la boucle d'évènements. Un QKeyEvent est nécessaire pour transmettre la touche Entrée, cependant la fonctionnalité Retour arrière (supprimer le caractère à gauche du curseur de saisie) pourrait tout aussi bien être mise en œuvre à l'aide d'un QInputMethodEvent :

1. QInputMethodEvent event;

2. event.setCommitString("", -1, 1);

4. QGuiApplication::sendEvent(m_focusObject, &event);

Puisque nous passons des valeurs non nulles comme deuxième et troisième paramètres de setCommitString(), le QInputEvent n'ajoutera pas les caractères donnés au contenu du widget de saisie, mais remplacera 1 caractère (replaceLength, 3e paramètre) à la position -1 (replaceFrom, 2e paramètre), ce qui signifie qu'un caractère à gauche de la position du curseur de saisie est remplacé par une chaîne de caractères vide (premier paramètre).

V - Réunir tous les éléments

Maintenant que nous avons le clavier virtuel et le plugin de méthode de saisie qui communique avec le clavier, voyons comment l'utiliser dans le cadre d'une application Qt réelle. Par défaut, le plugin QPA utilisé fournit une méthode de saisie pour le système, de sorte que si nous souhaitons utiliser notre propre méthode, nous devons l'indiquer explicitement à Qt en assignant à la variable d'environnement QT_IM_MODULE l'identifiant de la méthode de saisie. Dans notre cas, cet identifiant est 'vkim', c'est-à-dire précisément la valeur que nous avons stockée dans vkim.json comme métadonnées pour le plugin de méthode de saisie.

Pour utiliser Qt Designer avec notre propre clavier virtuel, il suffit d'exécuter les commandes suivantes en ligne de commande Linux :

1. # démarrer l'application d'interface utilisateur clavier

2. ./server

4. # définir la variable d'environnement

5. export QT_IM_MODULE=vkim

7. # exécuter une application Qt quelconque

8. designer

Maintenant, dès que vous cliquez sur un champ de saisie de texte dans Qt Designer, l'interface du clavier apparaîtra :

VI - Améliorations supplémentaires

Comme mentionné précédemment, cet exemple de mise en œuvre est vraiment très élémentaire et vise à vous présenter les concepts sous-jacents à cette technique sans vous noyer dans les détails. Pour créer un vrai clavier virtuel pouvant être utilisé sur un système en production, vous pouvez envisager d'ajouter les fonctionnalités suivantes :

- plusieurs configurations de clavier : cela signifie essentiellement que vous pouvez afficher des libellés différents sur les touches du clavier en fonction de la disposition configurée et renvoyer ces caractères dans la fonction keyToCharacter() ;

- position de la fenêtre du clavier : dans notre mise en œuvre, la position de la fenêtre du clavier à l'écran est fixée par le gestionnaire de fenêtres, ce qui évite habituellement toute superposition des fenêtres. Toutefois, pour le clavier virtuel, nous pourrions être amenés à l'ouvrir à proximité (au-dessus ou en dessous) du widget de saisie de texte pour éviter d'avoir à déplacer le curseur de la souris à l'autre bout de l'écran. QWidget::mapToGlobal() nous permet de déterminer la position à l'écran du widget cible de saisie et de placer l'interface clavier en conséquence en ajoutant une nouvelle méthode void setPosition(int x, int y) à l'interface D-Bus de la classe Keyboard.

VII - Ressources

Le code source de cet exemple est disponible à l'adresse https://github.com/KDAB/virtual-keyboard-demo.

Notes de la rédaction Developpez.com

Cet article (en anglais à l'origine) a été écrit par Tobias Koenig, ingénieur à KDAB.

Nos remerciements à KDAB pour l'autorisation à traduire et à publier ce tutoriel.

KDAB propose :

- des formations ;

- des conseils ;

- des développements ;

- de l'expertise C++, Qt et OpenGL.

Nous remercions David Faure pour la traduction, Jerôme pour la mise au gabarit et Claude Leloup pour sa relecture orthographique.