Page 2 sur 4

Re: Rediriger l'invite de commande dans une zone de texte

Publié : ven. 26/févr./2016 22:46
par Ollivier
NY152 a écrit :Est-ce PureBasic sait le faire. Aucune idée.
Si si, il sait le faire!

Entraine-toi avec un EditorGadget().
Tu lui colles 3 lignes :

"lundi"
"mardi"
"mercredi"

Le tout est de savoir si tu vas juste modifier la dernière ligne ("mercredi") ou bien si tu auras besoin de modifier les autres lignes.

Mon avis porte sur un tableau de chaînes ou une liste chaînée de chaînes qui servira de mémoire à ton affichage.

La subtilité réside dans le code de fin de ligne qui peut être:
- chr(10)
- chr(13)
- chr(13) + chr(10)
- chr(10) + chr(13)
C'est à vérifier une bonne fois pour toute pour EditorGadget() d'abord. (Après tu regarderas le code de fin de ligne de ta sortie de console)

Tu fais une procédure qui copie le tableau vers l'EditorGadget()
Ex : RefreshList()

Ensuite tu fais 4 fonctions pour gérer ce tableau de chaîne à partir de ta sortie de console.

Ex:
Clear_List() ; vide le tableau
Add_List(a$) ; Ajoute une ligne en fin de liste
Modify_List(a$) ; Change la dernière ligne
Grow_List(a$) ; Ajoute quelquechose en fin de dernière ligne

Là, toute la partie "Tableau vers EditorGadget()" est pensée.



Reste la partie "Console vers Tableau".

Il s'agit d'une lecture caractère par caractère de chaque chaîne de sortie de console (la console est un exemple de programme).

Ça semble lourd mais ce n'est pas bien compliqué.
Chaque caractère est extrait avec Mid(), converti en valeur de code ASCII avec a = Asc().
Par défaut, l'on affiche les caractères donc :
a$ + chr(a)
C'est le cas quand a > 31.

Si c'est un caractère système (a < 32), on suit les quelques règles ASCII ancestrales:
7 émet un signal sonore
9 tabulation
10 va en ligne suivante
12 efface l'écran
13 va en début de ligne

Il reste 3 codes à chercher dans la table ASCII dispo dans l'éditeur PureBasic :
- Aller en ligne précédente
- Aller en colonne précédente (équivalent d'une touche gauche)
- Aller en colonne suivante.

Quelque soit le code ASCII, le résultat pourra être traité par l'une des quatres fonctions Blabla_List() créées plus haut!

Après ça... Rien de plus, tout marchera!

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 4:10
par falsam
Ce code à compiler redirige l'invite de commande dans un GadgetEditor().

Vous allez pouvoir saisir les commandes console directement dans l'éditeur. Vous devez être sur la dernière ligne de l'éditeur.
Les flèches haut et bas ne sont pas opérationnelles.

Attention certaines commandes comme TIME sont bloquantes.

Essayer les commandes de gestion de dossiers comme CD, MD, etc .... un dir >result.txt fonctionne.

Les commandes ipconfig, ping, net start, help, etc .... fonctionnent.

N'oubliez pas ! ce code est loin d’être fonctionnel.

Code : Tout sélectionner

;Terminal : Rediriger l'invite de commande dans un gadget

Enumeration Font
  #FontGlobal
EndEnumeration

Enumeration Window
  #MainForm
EndEnumeration

Enumeration Gadget
  #Result
EndEnumeration

Enumeration KeyBoard
  #Up
  #Down
  #Return
EndEnumeration

Global Dim Cmds.s(0), Index.i


Declare Start()
Declare RunCmd(Cmd.s)
Declare OnReturn()
Declare OnKey()
Declare OnResize()

Start()

Procedure Start()
  LoadFont(#FontGlobal, "", 11)
  SetGadgetFont(#PB_Default, FontID(#FontGlobal))
  
  If OpenWindow(#MainForm, 0, 0, 800, 600, "Terminal", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget)
    EditorGadget(#Result, 5, 10, 790, 580)
    SetGadgetColor(#Result,  #PB_Gadget_BackColor, RGB(174, 191, 191))
    SetActiveGadget(#Result)
    
    AddKeyboardShortcut(#MainForm, #PB_Shortcut_Up, #Up)
    AddKeyboardShortcut(#MainForm, #PB_Shortcut_Down, #Down)
    AddKeyboardShortcut(#MainForm, #PB_Shortcut_Return, #Return)
    
    BindEvent(#PB_Event_Menu, @OnKey(), #MainForm, #Up)
    BindEvent(#PB_Event_Menu, @OnKey(), #MainForm, #Down)
    BindEvent(#PB_Event_Menu, @OnReturn(), #MainForm, #Return)
    
    BindEvent(#PB_Event_SizeWindow, @OnResize())
    ;BindGadgetEvent(#Result, @OnChange(), #PB_EventType_Change)
    
    RunCmd("echo Bienvenue ...")
    RunCmd("cd") ;Affiche le dossier courrant
    
    Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow
  EndIf
EndProcedure

Procedure RunCmd(Cmd.s)
  Protected prg.i, Stdout.s, TagResult.b
  Select LCase(cmd)
      
    Case "cls"
      ClearGadgetItems(#Result)
      
    Case "exit"
      End
      
    Default
      If LSet(Cmd, 2) = "cd"
        SetCurrentDirectory(Trim(Mid(cmd, 3)))
        AddGadgetItem(#Result, -1,  "Le dossier courrant est : " + GetCurrentDirectory())
        
      ElseIf LCase(LSet(cmd, 5)) = "title"
        SetWindowTitle(#MainForm, Trim(Mid(cmd, 6)))
        
      Else  
        
        prg = RunProgram("cmd.exe", "/C echo|CHCP 65001| " + Cmd, "", #PB_Program_Open|#PB_Program_Read|#PB_Program_Write|#PB_Program_Hide)
        
        If prg
          While ProgramRunning(prg)
            If AvailableProgramOutput(prg)
              TagResult = #True
              Stdout = ReadProgramString(prg)
              AddGadgetItem(#Result, -1,  Stdout)
            EndIf
          Wend
          
          CloseProgram(prg)
          
          If FindString(Cmd, ">") Or FindString(LCase(Cmd), "del")
            TagResult = #True
          EndIf
          
          If Not TagResult
            AddGadgetItem(#Result, -1,  "Erreur de commande : " + Cmd)
          EndIf
        EndIf
      EndIf
      AddGadgetItem(#Result, -1,  "")
  EndSelect
EndProcedure

Procedure OnReturn()
  Protected Buffer.s = GetGadgetItemText(#Result, CountGadgetItems(#Result)-1)
  
  SetGadgetState(#Result, CountGadgetItems(#Result)-1)  
  
  If Trim(Buffer)<>""
    Index = ArraySize(Cmds())
    Cmds(Index) = Buffer
    ReDim Cmds(Index + 1)
    RunCmd(Buffer)
  Else
    AddGadgetItem(#Result, -1, "")
  EndIf 
  
  SetGadgetState(#Result, CountGadgetItems(#Result)-1)
EndProcedure

;Obliger le curseur de saisie à rester sur la derniere ligne de l'éditeur 
;Fleche bas, haut
Procedure OnKey()     
  SetGadgetState(#Result, CountGadgetItems(#Result) - 1)
  
  Select EventMenu()
    Case 0 ;Fleche haut
      If Index < ArraySize(Cmds())
        Index + 1
      EndIf
      
    Case 1 ;Fleche bas
      If index > 0
        Index - 1
      EndIf
      
  EndSelect
  
  SetGadgetItemText(#Result, CountGadgetItems(#Result) - 1, Cmds(Index))
EndProcedure

Procedure OnResize()
  Protected Width = WindowWidth(#MainForm)
  Protected Height= WindowHeight(#MainForm)
  
  ResizeGadget(#Result, #PB_Ignore, #PB_Ignore, Width - 10, Height - 20)
EndProcedure

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 5:27
par Ollivier
Ah ça c'est bon ça l'EditorGadget() !

En remplaçant ReadProgramString() par ReadProgramData(), on peut alors récupérer les caractères système (de chr(0) à chr(31) ).

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 14:25
par Ollivier
Après, tu as le choix, soit tu "détectes tes frappes" dans l'EditorGadget()

comme ici (faut zapper le RTF)

Soit tu te fais un StringGadget() dédié à la saisie clavier. C'est bien pour tester le flux interface->console mais c'est moins design que l'EditorGadget().

Tu peux tester en runnant ton invite ainsi :

Code : Tout sélectionner

C:\>copy con test.txt[Enter]
je[Enter]
teste[Enter]
mon[Enter]
interface[Enter]
[F6]

C:\>exit[Enter]
Ça se fait avec WriteProgramData()

Vlà une liste explicative mais c'est principalement pour recevoir plutôt que d'émettre (chr(13) suffit la plupart du temps).

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 16:31
par falsam
Ollivier a écrit :Après, tu as le choix, soit tu "détectes tes frappes" dans l'EditorGadget()
Bonjour Ollivier. C'est ce que je fais dans le code que j'ai proposé.

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 17:18
par falsam
Petite mise à jour du code. Vous pouvez compiler avec la prise en charge unicode.
:arrow: http://www.purebasic.fr/french/viewtopi ... 73#p180973

En principe vous devez voir les accents correctement même si parfois .... non.

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 17:25
par Ollivier
Bonjour Falsam,

effectivement, tu détectes

1) l'équivalent d'une frappe sur [Enter]
ou
2) un BackSpace ultime qui vide un caractère resté en dernière ligne
ou
3) Une suppression de la dernière ligne via une des commandes du presse-papier (couper ou supprimer la sélection).

(2) et (3) sont des "bugs".

Il t'est possible de sophistiquer OnStart() pour ne répondre qu'aux commandes désirées (au moins la frappe standard)

Code : Tout sélectionner

Static.S Text, OldText
OldText = Text
Text = GetGadgetText(#Result)
If Text <> OldText
 ; Une touche a modifié le texte de l'EditorGadget
 
EndIf
C'est pour cela que j'évoque un tableau de chaînes plus haut (ou d'une liste chaîne de chaînes).
Ce tableau fonctionnerait à l'instar de OldText pour détecter quelle ligne est modifiée.

Soit c'est une modification normale (dernière ligne) dans ce cas l'on détecte s'il s'agit d'une validation (on peut sécuriser les bugs (2) et (3) en séquentialisant puisque le texte est mémorisé dans son ensemble par OldText et dans sa composition élémentaire par ce fameux tableau) et on l'envoie au programme sous-jacent.

Soit c'est une modification anormale (le mec s'est baladé dans l'éditeur et appuie sur une lettre) et, dans ce cas, on le recale en redéfinissant SetGadgetText(#Result, OldText) (ou OldText + DerniereFrappe$ pour plus d'ergonomie).

Cette sophistication t'évite d'externaliser les commandes vers PureBasic.

Tu "read" les datas, tu les affiches.

Tu détectes une modification de texte, tu la convertis en touche clavier (si normal) et tu la "write".

Et pis c'est marre!

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 17:28
par falsam
Ok Ollivier je comprends mieux expliqué comme ça :wink:

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 17:43
par Ollivier
Normalement, je pense que, grâce à cela ( {R/W}ProgramData() ), tu vas pouvoir dicerner l'ordre de ligne suivante (chr(13) + chr(10) ) de l'ordre de modification (systématiquement intégral, dans les coulisses, c'est un remplacement) de ligne (chr(13) seul), chose qu'a priori NY152 n'arrivait pas à atteindre.
(dixit "je vois des lignes qui se répètent les gars... Je me sens mal..." Etc...)

Re: Rediriger l'invite de commande dans une zone de texte

Publié : sam. 27/févr./2016 23:17
par falsam
Mise à jour du code précédent : Il est possible de faire défiler les commandes avec les flèches haut et bas du clavier.
:arrow: http://www.purebasic.fr/french/viewtopi ... 73#p180973

Re: Rediriger l'invite de commande dans une zone de texte

Publié : dim. 28/févr./2016 22:52
par Ollivier
Je n'ai pas trop compris à quoi ça sert cette MàJ, par rapport au but final?

A priori, à moins que je me goure, le but c'est d'éviter de prendre en charge les fonctions de l'invite de commande.

En plus, si tu utilises les flèches haut et bas, tu empêches une navigation dans le scope, alors que ça peut être remplacé par un menu popup.

J'ai un peu de mal à suivre.

Lire/Ecrire les datas plutôt que les strings c'est zapper toute ces prises en charge et réduire le RunProgram() à ce qu'il a de plus simple : "cmd.exe" (ou autre exécutable ouvert avec OpenRequester) sans paramètre.

En gros, le programme voulu est plus simple que ça...

Re: Rediriger l'invite de commande dans une zone de texte

Publié : dim. 28/févr./2016 23:07
par falsam
Ollivier a écrit :Je n'ai pas trop compris à quoi ça sert cette MàJ, par rapport au but final?
peut être que c'est moi dans ce cas qui est mal compris. Je me suis amusé à refaire trés sommairement la fenêtre de commandes windows en PureBasic.
Ollivier a écrit :En plus, si tu utilises les flèches haut et bas, tu empêches une navigation dans le scope
Tout comme la fenêtre de commande windows. Par contre tu peux naviguer dans le résultat d'une commande (Scroller, Souris, etc .....)
Ollivier a écrit :En gros, le programme voulu est plus simple que ça...
Ha bon ? Et si tu nous présentais un code dans ce cas ? :wink:

Re: Rediriger l'invite de commande dans une zone de texte

Publié : dim. 28/févr./2016 23:21
par falsam
NY152 a écrit :J'aimerais pouvoir "détourner" l'affichage d'un programme en invite de commande vers une zone de texte au sein d'une interface.
J'ai choisi de détourner l'affichage dans un editor gadget. Jusque là je pense que c'est bon.
NY152 a écrit :En gros, je ne veut pas le stdout mais le "vraie affichage" que reçoit l'invite de commande
Voila ce que j'ai compris :
1 - Saisir n'importe quel commande (Exemple DIR, CD, IPCONFIG, etc ....)
2 - Afficher le résultat d'une commande.
3 - j'ai ajouté le défilement des commandes avec les flèches haut et bas tout comme avec le teminal de commande.

Le code est loin d’être parfait et comporte des erreurs de conception. De plus le souci des accents n'est pas réglé.

Pour le moment je laisse en l'état en attendant les remarques de NY152. Si tu as un code à proposer alors n'hésite pas.

Re: Rediriger l'invite de commande dans une zone de texte

Publié : dim. 28/févr./2016 23:28
par Ollivier
Falsam a écrit :Ha bon ? Et si tu nous présentais un code dans ce cas ?
Rô t'es une flèche toi... Je n'ai pas le 230V la plupart du temps!

Juste démarre "cmd.EXE" sans param avec tous les canaux ouvert grâce à RunProgram() mais sans Hide pour commencer.

Comme indiqué en mp, le principal est d'obtenir un canal Data non muet (c'est la 1ère étape).

Donc, normalement, il doit te refourguer le prompt (la chaîne "C:\>") quand tu exécutes ReadProgramData(), c-à-d qu'après ce Read, PeekA(*Buffer) doit te retourner 67 (le "C" majuscule).

Est-ce le cas?

Re: Rediriger l'invite de commande dans une zone de texte

Publié : dim. 28/févr./2016 23:35
par falsam
Ollivier a écrit :Est-ce le cas?
Profite que tu sois en 220 V pour Ouvrir ton éditeur et vérifier.

Le temps que tu passes pour commenter ce que je fais et me poser des question en mp que tu pourrais trés bien poser sur le forum, t'aurais permis de tester et de poster ton code.