Probleme avec NSTask

lewelbylewelby Membre
02:56 modifié dans API AppKit #1
Bonjour,
je débute en programmation ObjectiveC cocoa etc ... J'ai besoin de faire un programme avec une interface graphique qui lance une application en ligne de commande. J'ai donc utilisé NSTask et NSPipe pour lancer l'application et lire les informations de la sortie standard et erreur de cette dernière. Cela fonctionne très j'en suis d'ailleurs un peu fier :) , maintenant je souhaite pouvoir interagir au clavier avec cette application. exemple touche n passe au fichier suivant, touche p au précédant. Je ne vois pas trop comment faire. Est ce que je dois faire avec un pipe sur l'entrée standard de l'application ? et comment coder les touches ?

Merci pour ce site plein d'informations indispensables.

Réponses

  • laudemalaudema Membre
    02:56 modifié #2
    dans 1242953143:

    Bonjour,
    je débute en programmation ObjectiveC cocoa etc ... J'ai besoin de faire un programme avec une interface graphique qui lance une application en ligne de commande. J'ai donc utilisé NSTask et NSPipe pour lancer l'application et lire les informations de la sortie standard et erreur de cette dernière. Cela fonctionne très j'en suis d'ailleurs un peu fier :) , maintenant je souhaite pouvoir interagir au clavier avec cette application. exemple touche n passe au fichier suivant, touche p au précédant. Je ne vois pas trop comment faire. Est ce que je dois faire avec un pipe sur l'entrée standard de l'application ? et comment coder les touches ?

    Merci pour ce site plein d'informations indispensables.

    Pour l'instant je ne suis qu'un grand débutant aussi j'espère que j'ai bien compris ce que tu voulais.

    L'appui sur une touche déclenche un AppleEvent, tu peux le détecter et connaà®tre le caractère grâce à  NSResponder ou le code via NSEvent file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/referencelibrary/Cocoa/idxEventsOtherInput-date.html

    Une fois que tu l'as détecté tu n'as plus qu'à  l'envoyer à  ton appli. Si tu as su lire stdOut et stdErr il te suffit maintenant d'avoir une référence à  stdIn non ?
    file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Conceptual/OperatingSystem/Concepts/task.html#//apple_ref/doc/uid/20000802-BBCJBDHC
    Et tu as deux exemples qui contiennent setStandardInput dans ton dossier Developer :  /Developer/Examples/Quartz\ Composer/Plugins/SQLiteQuery/ et /Developer/Examples/Quartz\ Composer/Plugins/CommandLineTool/

    Cordialement,

    Laurent
  • Philippe49Philippe49 Membre
    mai 2009 modifié #3
    Bienvenu !

    Ch 19 de Hillegas : Keyboard Events
    Pour interagir avec le keyboard, il faut accepter le statut de firstResponder,
    après tu as les méthodes voulues dans NSResponder (keyDown, keyUp, ...) et dans NSEvent (modifierFlags, characters ... )

    -(BOOL) acceptsFirstResponder { <br />	return YES;<br />}<br /><br />-(BOOL) becomeFirstResponder {<br />	return YES;<br />}<br />-(BOOL) resignFirstResponder {<br />	return YES;<br />}<br />
    


    mais le rapport avec NSTask, tu veux interagir avec le task via le clavier ?
  • Philippe49Philippe49 Membre
    mai 2009 modifié #4
    dans 1242975896:

    mais le rapport avec NSTask, tu veux interagir avec le task via le clavier ?


    Piste : Synchroniser des NSTextView dans ton application avec le stdin, stdout et le stderr du task ?
  • lewelbylewelby Membre
    02:56 modifié #5
    Merci pour vos réponses.
    Laudema je n'arrive pas à  compiler les exemples que tu m'as signaler j'ai sûrement du rater un truc car le bouton build / run n'est même pas actif .

    Philippe49 J'ai acheté le bouquin de Hillgass je vais lire le chapà®tre 19 en details merci.

    est ce bien le stdin qu'il faut utiliser ?
    il faut que je relise mes cours d'unix pour voir a quoi sert le standard input.

    Merci
  • laudemalaudema Membre
    02:56 modifié #6
    dans 1242980293:


    je n'arrive pas à  compiler les exemples que tu m'as signaler j'ai sûrement du rater un truc car le bouton build / run n'est même pas actif .


    Normal ce sont des plugins mais je te les ai donné en fait pour le code qu'on y trouve dans les fichiers .m, à  toi de t'en inspirer dans ta méthode.

    En fait tu as 4 classes à  découvrir NSTask + NSFileHandler et NSResponder + NSEvent ...
    Et si tu as le livre de Hillegass ça devrait aller encore mieux il y a presque tout ce qu'il faut, à  part le stdIn justement, mais page 412 tu as un exemple de lecture de stdOut qui montre le chemin. Me semble t-il ..
  • lewelbylewelby Membre
    02:56 modifié #7
    Je détail un peu le comportement attendu pour mon appli.
    Mon application devra récupérer les informations envoyer à  stdout et stderr par l'application en ligne de commande. De plus l'application en ligne de commande supporte une interaction au clavier par exemple si je presse la touche n elle passe au fichier suivant dans la liste des fichiers passé en parametre si je presse la touche p elle revient au précédent.

    J'ai donc utilisé NSTask pour lancer la tache, 2 NSPipe pour lire stdout et stderr cela fonctionne très bien avec un notificationcenter pour lire les informations en tache de fond sur les stdout et stderr.
    Mon soucis est comment simuler le comportement au clavier ?
    J'aimerai faire deux bouton Suivant et Précédant par exemple qui lorsque je dessus "envoie un message" à  l'application qui tourne en tache de fond equivalent a une pression sur les touches n ou p .
  • laudemalaudema Membre
    02:56 modifié #8
    dans 1243007993:

    Mon soucis est comment simuler le comportement au clavier ?
    J'aimerai faire deux bouton Suivant et Précédant par exemple qui lorsque je dessus "envoie un message" à  l'application qui tourne en tache de fond equivalent a une pression sur les touches n ou p .

    Avec des boutons ça devrait être encore plus facile ! Comme ça pas besoin de chercher l'événement clavier: il te suffit de l'affecter au bouton comme raccourci dans IB et de faire les méthodes qui vont avec ces boutons.
    Pour ça je ne saurais guère t'aider: je ne connais de NSTask que l'exercice que je te citais dans le bouquin de Hillegass et là  il n'y a que StdOut et err. Dans la doc et le livre ça passe par NSFilehandle et NSPipe: tu lances ta tâche en lui donnant un de ces objets en paramètre pour stdIn [maTask setStandardInput:monWriterPipe] et c'est par lui que tu pourras faire savoir depuis ton appli cocoa qu'il y a du nouveau à  traiter.
    Enfin c'est par là  que je commencerais mes tentatives: en adaptant ce qui fonctionne déjà , si tu sais lire prend donc le même chemin pour écrire !
    Regarde là  file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Reference/Foundation/Classes/NSPipe_Class/Reference/Reference.html#
    et ici file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Reference/Foundation/Classes/NSFileHandle_Class/Reference/Reference.html#//apple_ref/occ/instm/NSFileHandle/writeData:
    Il y a un lien pour un exemple sur ce dernier.
  • AliGatorAliGator Membre, Modérateur
    02:56 modifié #9
    Oui ensuite il suffit d'écrire @n ou @p dans le monWriterPipe ;)
  • lewelbylewelby Membre
    02:56 modifié #10
    Merci pour vos réponses.
    j'ai testé mais cela ne fonctionne pas.
    Je me demande si l'application n'attend pas le code des touches n et p au lieu des carateres n et p ?

    par exemple j'ai testé de lancer l'application top qui normalement dans un shell se termine lorsque l'on clic sur la touche q. et bien si j'envoie @q elle ne quitte pas :)

  • laudemalaudema Membre
    02:56 modifié #11


    dans 1243014247:

    par exemple j'ai testé de lancer l'application top qui normalement dans un shell se termine lorsque l'on clic sur la touche q. et bien si j'envoie @q elle ne quitte pas :)

    C'est le q seul j'espère que tu envoies ;) Ceci dit j'utiliserais plutôt cat que top pour faire ces essais : avec cat tu peux lire ce que tu envoies, ça te permettrait de t'assurer que quelque chose arrive par ce moyen.
    Il peut y avoir plusieurs raison pour lesquelles ça ne fonctionne pas (encore ;-): ça n'est pas écrit dans le pipe, ça n'est pas relu, ça n'est pas le caractère attendu. Top attend un caractère du terminal mais le terminal est il alors considéré comme stdIn ?
    Pour ces raisons cat me semble plus facile pour voir si "ça marche" ou pas.
    Jusque maintenant la doc a toujours eu raison contre moi ...

    PS: je n'ai pas le temps de faire des essais ni des recherches pour toi mais tu pourrais aussi tenter Google " cocoa writedata pipe standardInput demo code " Amha tu n'es pas le premier confronté à  ce genre de problème ...
  • lewelbylewelby Membre
    02:56 modifié #12
    Merci pour ta réponse bonne idée le test avec cat au bout d'un moment je n'avais plus d'idée pour trouver une solution.
    Je vois bien les caractère que j'envoie revenir sur la sortie standard donc mes pipes fonctionnent correctement. C'est juste que l'application ne gère pas ces informations elle attend une touche et pas un caractère.
    J'ai posté la question sur la mailing liste cocoa-dev-request ils m'ont répondu que je devais faire un pty.
    Je vais chercher comment on fait ca.

  • Philippe49Philippe49 Membre
    02:56 modifié #13
    Tout cela me semble super compliqué. Pourquoi ne pas utiliser un bouton pour passer d'un fichier à  un autre ?
    Tu veux reconstruire un terminal qui lance un shell, qui sous le shell lance un exécutable, ou tu veux seulement lancer un exécutable ? Parce que ce n'est pas l'exécutable qui répond directement aux touches q ou Ctrl C ou n ...
  • lewelbylewelby Membre
    mai 2009 modifié #14
    Comme un ptit bout de code vaut mieux que de longure explication voici ce que je fais.

    task = [[NSTask alloc] init];<br />[task setLaunchPath:@&quot;/opt/local/bin/uade123&quot;];<br />NSArray *args = [NSArray arrayWithObjects:@&quot;-s&quot;,[NSString stringWithFormat:@&quot;%d&quot;,currentSub], songName,&nbsp; nil];<br />
    


    je lance l'application /opt/..... et c'est elle qui ne répond pas à  mes touches.
    j'ai testé en lancant cat à  la place pas de problème je recois les echo des touches que je frappe donc mes pipes fonctionnent correctement.

    En esperant que cela sera plus clair.
    <3
  • Philippe49Philippe49 Membre
    02:56 modifié #15
    Bon voyons tout d'abord du côté application .
    Quel est ton code pour créer le fileHandle ?
    Quel est ton code pour récupérer le texte/data que tu veux transmettre à  l'exécutable ?
    Quel est ton code pour l'envoyer ?
  • lewelbylewelby Membre
    02:56 modifié #16
    alors voici un bout du code:

    //creer le nouveau pipe.
    pipeout = [[NSPipe alloc] init];
    pipein = [[NSPipe alloc] init];
    // stdout et stderr utilise pipeout
    [task setStandardOutput:pipeout];
    [task setStandardInput:pipein];
    fhout = [pipeout fileHandleForReading];
    fhin = [pipein fileHandleForWriting];
    ...
    ...

    Pour envoyer le texte j'ai un truc comme ca, déclenché par le clic sur un bouton:
    indata = [@n dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
    if (task)
    {
        [fhin writeData:indata];
    }

    Voila
    <3
  • Philippe49Philippe49 Membre
    02:56 modifié #17
    Et quand tu envoies le "n", le task est toujours en action ?

    NSNotificationCenter * defaultCenter=[NSNotificationCenter defaultCenter];<br />	[defaultCenter addObserver:self selector:@selector(taskDidStop:) name:NSTaskDidTerminateNotification object:task];<br />
    



    -(void) taskDidStop:(NSNotification*) notification {<br />	[fhin release];<br />	[fhout release];<br />	[task release];<br />	task=nil;<br />	NSLog(@&quot;task terminated&quot;);<br />}
    
Connectez-vous ou Inscrivez-vous pour répondre.