Utiliser IOKit pour simuler une frappe au clavier
letof
Membre
Bonjour,
Je souhaiterai émettre une chaà®ne de caractères en saisie de l'application qui a le focus utilisateur.
Une solution existe avec appleScript, en envoyant un ordre keystroke à un certain processus, mais elle ne me convient pas, car elle n'est valable qu'avec les applications scriptables !
Je me suis donc tourné vers IOKit.
J'ai réussi à envoyer un keyCode, qui est parfaitement reçu par l'application courante. Mais ce keyCode ne correspond pas à un caractère, mais à une touche du clavier.
Or l'exemple d'apple (en fichier joint) m'a fait croire le contraire. De plus, il me semble qu'il ne marche pas, du moins chez moi ( Mac OS 10.4.9 ) car je reçu toujours le même caractère q ( keyCode 0 )
Aurais je oublié quelque chose ?
Y a-t-il eu des modifications depuis les précédentes versions de l'OS ?
Y a-t-il d'autres CharSet à spécifier ?
Si quelqu'un avait une expérience sur ce problème à me faire partager, ce serait gentil.
Merci de votre aide,
letof.
Pour ceux que ça interresse, le code du fichier joint se compile et s'execute comme ceci dans le Terminal :
sleep 4 vous donne le temps de vous placer sur TextEdit pour observer l'effet.
PS j'ai trouvé un post récent d'un autre forum, sur l'utilisation de IOHIDPostEvent pour un événement souris qui fonctionne très bien.
PS2 j'ai moi même parfaitement controlé la touche eject lors de mes tests.
PS3 pour contourner mon problème, j'ai dû 'mappé' les caractères pour en obtenir la correspondance keyCode, mais je suis limité aux minuscules, et à la moitié des caractères. Cette solution reste du bricolage, que je souhaite temporaire.
Je souhaiterai émettre une chaà®ne de caractères en saisie de l'application qui a le focus utilisateur.
Une solution existe avec appleScript, en envoyant un ordre keystroke à un certain processus, mais elle ne me convient pas, car elle n'est valable qu'avec les applications scriptables !
Je me suis donc tourné vers IOKit.
J'ai réussi à envoyer un keyCode, qui est parfaitement reçu par l'application courante. Mais ce keyCode ne correspond pas à un caractère, mais à une touche du clavier.
Or l'exemple d'apple (en fichier joint) m'a fait croire le contraire. De plus, il me semble qu'il ne marche pas, du moins chez moi ( Mac OS 10.4.9 ) car je reçu toujours le même caractère q ( keyCode 0 )
Aurais je oublié quelque chose ?
Y a-t-il eu des modifications depuis les précédentes versions de l'OS ?
Y a-t-il d'autres CharSet à spécifier ?
Si quelqu'un avait une expérience sur ce problème à me faire partager, ce serait gentil.
Merci de votre aide,
letof.
Pour ceux que ça interresse, le code du fichier joint se compile et s'execute comme ceci dans le Terminal :
<br />mv testHID.txt testHID.cc<br />g++ testHID.cc -o testHID -framework IOKit<br /><br />sleep 4 ; ./testHID<br />
sleep 4 vous donne le temps de vous placer sur TextEdit pour observer l'effet.
PS j'ai trouvé un post récent d'un autre forum, sur l'utilisation de IOHIDPostEvent pour un événement souris qui fonctionne très bien.
PS2 j'ai moi même parfaitement controlé la touche eject lors de mes tests.
PS3 pour contourner mon problème, j'ai dû 'mappé' les caractères pour en obtenir la correspondance keyCode, mais je suis limité aux minuscules, et à la moitié des caractères. Cette solution reste du bricolage, que je souhaite temporaire.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Pour les minuscules/majuscules, tu dois poster un événement clavier "touche shift pressée" en premier, suivi de l'événement clavier "touche normale".
Idem pour les touches mortes (cà d envoyer les caractères accentués, surtout ceux avec ^ et ¨), où tu dois d'abord émettre l'événement de la touche morte puis celui de la touche du caractère à accentué.
.
Notamment, depuis 10.4 (ou 10.5, je ne sais plus), tu as la possibilité d'envoyer des chaines de caractères (unicode) en tant qu'événement clavier, ce qui simplifie notablement les choses.
.
Avec IOKit ça devient 'de la bidouille', car je dois remplacer chaque caractère par sa séquence clavier.
C'est pas glop
Je vais de ce pas me tourner vers Quartz
Merci encore.
Je suis en train de regarder en utilisant Quartz Event Service, et il me semble que je suis toujours tributaire du type de clavier.
J'ai tapé ça pour l'instant, mais n'étant pas sur mac au travail ... je ne le testerai que ce Week end.
Enfin si ça tente quelqu'un d'essayer :
Merci de votre intérêt.
poster l'événement dans le window server !
Ceci se fait par CGEventPost (c'est le système qui se chargera d'envoyer ces événements à l'appli qui va bien - celle au premier plan -), ou par CGEventPostToPSN pour n'envoyer les événements qu'à une appli précise (même si elle n'est pas active - au premier plan-).
Je testerai ton code ce soir.
D'autre part, faut essayer la fonction CGEventKeyboardSetUnicodeString qui, théoriquement, permet de préciser l'envoi des événements clavier à partir d'une chaine de caractère au lieu de passer par les codes clavier.
.
CGEventPost logique ! :)beta:
par contre CGEventKeyboardSetUnicodeString prend un événement en paramétre. Cette événement doit être un événement clavier. Comme créer cet événement autrement qu'avec CGEventCreateKeyboardEvent ??
J'avoue que la doc Apple est plus que succincte.
Merci.
Au pire, j'ai dans mes archives un bout de code que j'avais écrit d'antan jadis pour convertir un caractère ascii en une séquence de codes clavier pour l'obtenir.
J'utilisais alors la ressource KCHR (aujourd'hui, ce serait plutôt uchr) de manière inversée.
Je ne sais pas si aujourd'hui, c'est toujours d'actualité, d'autant plus que 10.5 a rendu beaucoup de fonctions carbon deprecated...
.
Je reviens sur ce que j'ai fait ce week-end,
Le code que j'ai mis ici est la base de tout ce que j'ai essayé.
Création d'un événement clavier (keyCode 6 comme dans les exemples : CGEventKeyboardGetUnicodeString me rend bien 'w' comme chaine), puis affectation d'une chaine par CGEventKeyboardSetUnicodeString. => La chaine est bien enregistrée quelque part (CGEventKeyboardGetUnicodeString me réponds bien ma chaine), mais au CGPostEvent, j'ai toujours mon keyCode 6 ('w' clavier francais)
J'ai essayé aussi de partir d'un événement vide (CGCreateEvent) puis de lui affecté le type clavier, est enfin d'y affecter une chaine, mais rien n'y fait, au CGPostEvent, je vois apparaitre 'q' (keyCode 0 du clavier francais)
Donc je suppose qu'il doit y avoir une routine autre que CGPostEvent à appeler pour générer les séquences clavier correspondantes à la chaine Unicode. Mais laquelle ?
Je n'ai pas essayé avec CGEventPostToPSN, mais il ne me semble pas qu'elle soit différente de CGPostEvent, à part le process en paramètre.
Je recherche une autre solution, et si je la trouve, je vous la transmets.
A suivre...
A priori, CGEventKeyboardSetUnicodeString est buggé sous 10.4, et ne fonctionne donc pas correctement.
Il faut donc passer par un classique CGEventCreateKeyboardEvent.
N'ayant pas encore installé 10.5, je ne peux pas savoir si c'est ok sous cette version.
Concernant cette dernière fonction, 2 problèmes se posent :
- utiliser des les codes clavier.
- attacher le "bon clavier".
Pour le second point, il faut surtout ne pas oublier de mettre le bon id de clavier dans l'événement, afin que le système puisse faire correctement le mappage.
Ceci se fait en utilisant la fonction CGEventSourceSetKeyboardType.
Si tu ne précises pas ça, c'est le clavier "par défaut" qui est utilisé, donc le clavier US (voir la console au démarrage).
Pour le premier point, je suis en train de construire la fonction inverse à UCKeyTranslate, cà d à partir d'un caractère unicode, retrouver la séquence de code clavier à générer.
Ceci se fait en passant par les tables de mappage prséentes dans la ressource uchr.
.
Je me pose quand même une question : Quel est l'intérêt d'une fonction buggé ? Elle a été introduite pour répondre à un besoin. Donc certaines personnes doivent vouloir l'utiliser (j'ai trouvé une question identique à la mienne sur list.apple.com, mais la réponse ne me convenait pas car sans explication, il était proposé de passer par les keyCodes 1 par 1) Un bug non résolu sur 10 mises à jour majeures, signifierai que la fonction n'est finalement utile à pas grand monde. Donc pourquoi l'avoir introduite ?
Donc j'en reviens à l'existence d'une routine (peut être cachée) qui permet à partir d'un événement clavier affublé d'une chaine Unicode, d'être convertie en événement clavier.
Sinon, pour le type de clavier, il ne m'est pas nécessaire d'avoir le clavier Français ; il me suffit de générer les keyCodes avec le même type de clavier que celui qui servira à les interpréter. Un clavier qui me permette les lettres accentuées.
Merci Bru de ton aide, mais transmets moi juste les infos que tu as sur uchr, je m'en contenterai pour une fonction UCKeyTranslateInverse.
La doc apple précise bien ( mais comme c'est en anglais, ça ne m'a pas sauté aux yeux ) que CGEventKeyboardSetUnicodeString ASSOCIE une chaine à un événement, mais que celle-ci est ignoré par le traitement de l'événement, au profit du keyCode. Donc ce n'est pas adapté à mon problème.
On en revient donc à UCKeyTranslateInverse.
Après quelques essais infructueux, mais une recherche intensive, j'ai trouver ça :
http://svn.python.org/projects/external/tk8.4.12/macosx/tkMacOSXKeyEvent.c
Dès fois que ce soit utile pour d'autres.
Moi je vais de ce pas tester tout ça.
A bientôt.
Je suis en train de le ré-écrire pour prendre en compte la ressource uchr (au lieu de KCHR).
.
(Bon j'avoue que je suis pas non plus allé chercher sur mon mac -- que je n'ai d'ailleurs pas sous la main en ce moment -- comment était foutus les fichiers de clavier)
Les ressources keyboard layout peuvent être sous forme de ressources traditionnelles, ou sous forme de fichier xml à mettre dans Library/Keyboard.
L'API de gestion des claviers de OS X fournit par chance une fonction haut-niveau qui permet de récupérer le contenu de ladite ressource, quelque soit son format/emplacement.
Donc, pas besoin de se prendre le chou.
.
D'après ce que j'ai lu, les ressources KCHR ne serait pas complètement abandonnées. Sans doute pour ne les pas réécrire pour les anciens claviers. Dans tous les codes que j'ai récupéré, les 2 types de ressources sont gérées. Alors je ne sais pas encore si c'est utile. En tout cas, j'ai un clavier d'iMac G3 émeraude (existe-t-il plus vieux sur le marché ?), et j'ai bien un uchr renseigné.
Par contre, je n'ai pas encore cerné la structure interne d'uchr. J'y ai trouvé des caractères ASCII rangé par ordre de keyCodes, mais pas de caractères étendus, ni les combinaisons de touches.
Qu'arrives tu à y décrypter ?
J'ai retrouvé une partie du code que j'avais écrit pour faire la conversion ASCII vers KEYCODE.
Je l'ai adapté à 10.4 (il était écrit à l'époque de Système 7) et je l'ai commenté :
La fonction retourne YES si la conversion a eu lieu, sinon NO (code ASCII inconnu dans l'encodage Mac OS Roman, ou ASCII formé à partir des touches mortes).
Le premier paramètre est le caractère ASCII en Mac OS Roman, et les 3 suivants sont les pointeurs vers le key-code retourné et l'état des touches modificatrices pour obtenir le caractère.
Pour les touches modificatrices, j'avais une seconde fonction... Je ne la retrouve pas pour le moment pour le moment.
Enjoy.
.
Ici, j'envoie les événements "key" à l'appli dont le pid est 1163 (il s'agit de TextEdit pour mon test).
.