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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
#include
<QApplication>
#include
<QDBusConnection>
#include
"keyboard.h"
int
main(int
argc, char
**
argv)
{
QApplication
app(argc, argv);
if
(!
QDBusConnection
::
sessionBus().registerService("com.kdab.inputmethod"
)) {
qFatal
("Unable to register at DBus"
);
return
1
;
}
Keyboard keyboard;
if
(!
QDBusConnection
::
sessionBus().registerObject("/VirtualKeyboard"
, &
keyboard, QDBusConnection
::
ExportAllSignals |
QDBusConnection
::
ExportAllSlots)) {
qFatal
("Unable to register object at DBus"
);
return
1
;
}
return
app.exec();
}
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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
class
Keyboard : public
QWidget
{
Q_OBJECT
public
:
explicit
Keyboard(QWidget
*
parent =
Q_NULLPTR
);
public
slots
:
void
showKeyboard();
void
hideKeyboard();
bool
keyboardVisible() const
;
signals
:
void
specialKeyClicked(int
key);
void
keyClicked(const
QString
&
text);
private
slots
:
void
buttonClicked(int
key);
}
;
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()).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
Keyboard::
Keyboard(QWidget
*
parent)
:
QWidget
(parent)
{
setWindowFlags(Qt
::
WindowDoesNotAcceptFocus |
Qt
::
Tool |
Qt
::
FramelessWindowHint |
Qt
::
WindowStaysOnTopHint);
QGridLayout
*
gridLayout =
new
QGridLayout
(this
);
QSignalMapper
*
mapper =
new
QSignalMapper
(this
);
connect
(mapper, SIGNAL
(mapped(int
)), SLOT
(buttonClicked(int
)));
int
row =
0
;
int
column =
0
;
for
(int
i =
0
; i <
layoutSize; ++
i) {
if
(keyboardLayout[i].key ==
NEXT_ROW_MARKER) {
row++
;
column =
0
;
continue
;
}
QPushButton
*
button =
new
QPushButton
;
button->
setFixedWidth(40
);
button->
setText(QString
::
fromLatin1(keyboardLayout[i].label));
mapper->
setMapping(button, keyboardLayout[i].key);
connect
(button, SIGNAL
(clicked()), mapper, SLOT
(map()));
gridLayout->
addWidget(button, row, column);
column++
;
}
}
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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
#define NEXT_ROW_MARKER 0
struct
KeyboardLayoutEntry{
int
key;
const
char
*
label;
}
;
KeyboardLayoutEntry keyboardLayout[] =
{
{
Qt
::
Key_1, "1"
}
,
{
Qt
::
Key_2, "2"
}
,
{
Qt
::
Key_3, "3"
}
,
{
Qt
::
Key_4, "4"
}
,
{
Qt
::
Key_5, "5"
}
,
{
Qt
::
Key_6, "6"
}
,
{
Qt
::
Key_7, "7"
}
,
{
Qt
::
Key_8, "8"
}
,
{
Qt
::
Key_9, "9"
}
,
{
Qt
::
Key_0, "0"
}
,
{
Qt
::
Key_Backspace, "<-"
}
,
{
NEXT_ROW_MARKER, 0
}
,
{
Qt
::
Key_Q, "q"
}
,
{
Qt
::
Key_W, "w"
}
,
...
}
;
const
static
int
layoutSize =
(sizeof
(keyboardLayout) /
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é :
2.
3.
4.
5.
6.
7.
void
Keyboard::
buttonClicked(int
key)
{
if
((key ==
Qt
::
Key_Enter) ||
(key ==
Qt
::
Key_Backspace))
emit
specialKeyClicked(key);
else
emit
keyClicked(keyToCharacter(key));
}
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 :
2.
3.
4.
5.
6.
7.
8.
9.
static
QString
keyToCharacter(int
key)
{
for
(int
i =
0
; i <
layoutSize; ++
i) {
if
(keyboardLayout[i].key ==
key)
return
QString
::
fromLatin1(keyboardLayout[i].label);
}
return
QString
();
}
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.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
void
Keyboard::
showKeyboard()
{
QWidget
::
show();
}
void
Keyboard::
hideKeyboard()
{
QWidget
::
hide();
}
bool
Keyboard::
keyboardVisible() const
{
return
QWidget
::
isVisible();
}
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 :
- Mettre en œuvre une version personnalisée de la sous-classe QPlatformInputContext ;
- 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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
class
QVkImPlatformInputContextPlugin
: public
QPlatformInputContextPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA
(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface"
FILE "vkim.json"
)
public
:
QVkImPlatformInputContext
*
create(const
QString
&
, const
QStringList
&
) Q_DECL_OVERRIDE
;
}
;
QVkImPlatformInputContext
*
QVkImPlatformInputContextPlugin
::
create(const
QString
&
system, const
QStringList
&
paramList)
{
Q_UNUSED
(paramList);
if
(system ==
QLatin1String
("vkim"
)) {
return
new
QVkImPlatformInputContext
;
}
return
0
;
}
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 :
2.
3.
{
"Keys"
:
[
"vkim"
]
}
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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
class
QVkImPlatformInputContext
: public
QPlatformInputContext
{
Q_OBJECT
public
:
QVkImPlatformInputContext
();
~
QVkImPlatformInputContext
();
bool
isValid() const
Q_DECL_OVERRIDE
;
void
setFocusObject(QObject
*
object) Q_DECL_OVERRIDE
;
void
showInputPanel() Q_DECL_OVERRIDE
;
void
hideInputPanel() Q_DECL_OVERRIDE
;
bool
isInputPanelVisible() const
Q_DECL_OVERRIDE
;
private
slots
:
void
keyboardSpecialKeyClicked(int
key);
void
keyboardKeyClicked(const
QString
&
character);
private
:
QDBusInterface
*
m_keyboardInterface;
QObject
*
m_focusObject;
}
;
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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
QVkImPlatformInputContext
::
QVkImPlatformInputContext
()
:
m_focusObject(0
)
{
m_keyboardInterface =
new
QDBusInterface
("com.kdab.inputmethod"
,
"/VirtualKeyboard"
,
"local.server.Keyboard"
,
QDBusConnection
::
sessionBus(),
this
);
connect
(m_keyboardInterface, SIGNAL
(keyClicked(QString
)),
SLOT
(keyboardKeyClicked(QString
)));
connect
(m_keyboardInterface, SIGNAL
(specialKeyClicked(int
)),
SLOT
(keyboardSpecialKeyClicked(int
)));
}
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.
2.
3.
4.
bool
QVkImPlatformInputContext
::
isValid() const
{
return
m_keyboardInterface->
isValid();
}
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.
2.
3.
4.
void
QVkImPlatformInputContext
::
setFocusObject(QObject
*
object)
{
m_focusObject =
object;
}
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).
2.
3.
4.
5.
6.
7.
8.
9.
void
QVkImPlatformInputContext
::
showInputPanel()
{
m_keyboardInterface->
call("showKeyboard"
);
}
void
QVkImPlatformInputContext
::
hideInputPanel()
{
m_keyboardInterface->
call("hideKeyboard"
);
}
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 :
2.
3.
4.
5.
6.
7.
8.
9.
bool
QVkImPlatformInputContext
::
isInputPanelVisible() const
{
const
QDBusReply
<
bool
>
reply =
m_keyboardInterface->
call("keyboardVisible"
);
if
(reply.isValid())
return
reply.value();
else
return
false
;
}
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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
void
QVkImPlatformInputContext
::
keyboardKeyClicked(const
QString
&
characters)
{
if
(!
m_focusObject)
return
;
QInputMethodEvent
event;
event.setCommitString(characters);
QGuiApplication
::
sendEvent(m_focusObject, &
event);
}
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.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
void
QVkImPlatformInputContext
::
keyboardSpecialKeyClicked(int
key)
{
if
(!
m_focusObject)
return
;
if
(key ==
Qt
::
Key_Enter) {
QKeyEvent
*
pressEvent =
new
QKeyEvent
(QEvent
::
KeyPress,
Qt
::
Key_Enter,
Qt
::
NoModifier);
QGuiApplication
::
postEvent(m_focusObject, pressEvent);
QKeyEvent
*
releaseEvent =
new
QKeyEvent
(QEvent
::
KeyRelease,
Qt
::
Key_Enter,
Qt
::
NoModifier);
QGuiApplication
::
postEvent(m_focusObject, releaseEvent);
}
else
if
(key ==
Qt
::
Key_Backspace) {
QKeyEvent
*
pressEvent =
new
QKeyEvent
(QEvent
::
KeyPress,
Qt
::
Key_Backspace,
Qt
::
NoModifier);
QGuiApplication
::
postEvent(m_focusObject, pressEvent);
QKeyEvent
*
releaseEvent =
new
QKeyEvent
(QEvent
::
KeyRelease,
Qt
::
Key_Backspace,
Qt
::
NoModifier);
QGuiApplication
::
postEvent(m_focusObject, releaseEvent);
}
}
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 :
2.
3.
4.
QInputMethodEvent
event;
event.setCommitString(""
, -
1
, 1
);
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 :
2.
3.
4.
5.
6.
7.
8.
# démarrer l'application d'interface utilisateur clavier
./server
# définir la variable d'environnement
export QT_IM_MODULE
=
vkim
# exécuter une application Qt quelconque
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.