Página 1 de 1

Leer comandos del usuario en la consola

Publicado: 14 Nov 2017, 18:03
por Jonny
Hola,

Estoy haciendo una aplicación en modo consola, que debería de admitir comandos del usuario.

Debe ser una tontería, pero he probado de todas las formas que se me han ocurrido a leer datos de la consola, y no puedo: es como si el CMD se quedase bloqueado por mi programa, porque no responde a nada. tanto da que ejecute directamente el programa y se abra la consola, como que ejecute el CMD.exe, y desde él, el programa.

He probado con unas funciones que encontré hace ya tiempo por aquí, de Nahuel, que funcionan bien, salvo Scanf, que si la llamo dentro de un While 1...Wend, no devuelve nada.

He probado con una UDF para la consola del foro inglés (que no funciona porque la función Cin() da error) y con STDOutRead, para leer del proceso del CMD, y con todo, el resultado es el mismo: Nunca obtengo datos de la consola, porque es como que se queda bloqueada y no responde.

Supongo que por el While 1...Wend que tiene el programa para mantenerse en ejecución.

Lo curioso es, que si intento leer la consola desde ese mismo bucle el resultado es el mismo.

Escribir en la consola sí puedo hacerlo bien.

¿Cómo puedo hacer para leer los comandos que introduzca el usuario en la consola, para poder procesarlos y devolverle una respuesta, volver a leer comandos eTC, sin que se bloquee la consola?.

Salu2!

Re: Leer comandos del usuario en la consola

Publicado: 16 Nov 2017, 11:27
por Jonny
Me respondo:

Buscando y buscando en el foro inglés, encontré algo que por fin me funcionó.

Sólo uso la primera función, pero las tres son muy útiles.

Podría haber otra simplemente para imprimir texto en la consola, por aquello de hacerlo todo con la misma UDF, pero se puede tirar de ConsoleWrite() para eso.

Hace pocos días encontré unas funciones de consola, entre las que había una función para imprimir texto en la consola, que me gustó porque los acentos y caracteres especiales se veían bien, a diferencia de ConsoleWrite()... Pero como lo que necesitaba, que era leer de la consola no funcionaba, borré la UDF.

Igual la vuelvo a buscar y la comparto por si a alguien le sirve por lo de mostrar acentos en la consola.

No me gustó que era un poco lío el código, porque iniciaba la consola por un lado (no sé para qué, porque no hacía cosas importantes para que las demás funciones trabajasen correctamente), luego las demás funciones tenían un IF para controlar si había que "crear una consola" ...

Pero lo importante es que el texto se imprimía en pantalla usando un API de Windows.

Aquí va el código con el que he conseguido leer lo que introduce el usuario en la consola, y lo mejor de todo: en un bucle infinito para mantener el programa activo, y sin que se bloquee la consola como comentaba en el mensaje anterior.

Código: Seleccionar todo

#AutoIt3Wrapper_Change2CUI=y


; #FUNCTION# ====================================================================================================
; Name...........:  _ConsoleGetInput
; Description....:  Get user input from the console
; Syntax.........:  _ConsoleGetInput([$sPrompt = ""[, $iLen = 0[, $autoReturn = False[, $validateEach = ""[, $validateFinal = ""[, $hideInput = False[, $maskChar = ""]]]]]]])
; Parameters.....:  $sPrompt        - [Optional] Prompt text to display before input
;                   $iLen           - [Optional] Maximum length of input
;                   $autoReturn     - [Optional] Automatically return when $iLen is reached
;                   $validateEach   - [Optional] Regular expression to validate each character as it is input
;                   $validateFinal  - [Optional] Regular expression to validate the final input
;                   $hideInput      - [Optional] Do no print input characters
;                   $maskChar       - [Optional] If $hideInput is true, the character to print instead of input
;
; Return values..:  Success - Input string
;                   Failure - Empty string
; Author.........:  Erik Pilsits
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _ConsoleGetInput($sPrompt = "", $iLen = 0, $autoReturn = False, $validateEach = "", $validateFinal = "", $hideInput = False, $maskChar = "")
    $iLen = Abs($iLen)
    $maskChar = StringLeft($maskChar, 1)
    If $sPrompt <> "" Then ConsoleWrite($sPrompt)
    Local $sChars = "", $sIn, $aErase[3] = [ChrW(8), " ", ChrW(8)]
    While True
        $sIn = DllCall("msvcrt.dll", "int:cdecl", "_getwch")
        If $sIn[0] < 32 Then
            ; control characters
            Switch $sIn[0]
                Case 13 ; ENTER
                    ; validate if no length or length not reached
                    ; otherwise validation was performed upon input
                    If ($validateFinal <> "") And ((Not $iLen) Or (StringLen($sChars) < $iLen)) Then
                        If Not StringRegExp($sChars, $validateFinal, 0) Then
                            ; failed validation
                            ; erase entire input
                            If Not $hideInput Or ($hideInput And ($maskChar <> "")) Then
                                For $i = 0 To 2
                                    For $j = 1 To StringLen($sChars)
                                        ConsoleWrite($aErase[$i])
                                    Next
                                Next
                            EndIf
                            $sChars = ""
                            ContinueLoop
                        EndIf
                    EndIf
                    ; no validation or passed validation
                    ExitLoop
                Case 8 ; BACKSPACE
                    If $sChars <> "" Then
                        If Not $hideInput Or ($hideInput And ($maskChar <> "")) Then ConsoleWrite(ChrW(8) & " " & ChrW(8))
                        $sChars = StringTrimRight($sChars, 1)
                    EndIf
                Case 27 ; ESCAPE
                    Return ""
            EndSwitch
        Else
            ; printable characters
            ; length reached, do nothing
            If $iLen And (StringLen($sChars) >= $iLen) Then ContinueLoop
            ; get character
            $sIn = ChrW($sIn[0])
            ; validate each character?
            If ($validateEach <> "") And (Not StringRegExp($sIn, $validateEach, 0)) Then ContinueLoop
            $sChars &= $sIn
            ; always validate when length reached
            If ($validateFinal <> "") And $iLen And (StringLen($sChars) >= $iLen) Then
                If Not StringRegExp($sChars, $validateFinal, 0) Then
                    ; failed validation
                    ; erase last char input, do not print
                    $sChars = StringTrimRight($sChars, 1)
                    ContinueLoop
                EndIf
            EndIf
            ; no validation or passed validation or no length or length not reached
            ; print character?
            If Not $hideInput Then
                ConsoleWrite($sIn)
            ElseIf $hideInput And ($maskChar <> "") Then
                ConsoleWrite($maskChar)
            EndIf
            ; autoReturn?
            If $autoReturn And $iLen And (StringLen($sChars) >= $iLen) Then ExitLoop
        EndIf
    WEnd
    Return $sChars
EndFunc   ;==>_ConsoleGetInput

; #FUNCTION# ====================================================================================================
; Name...........:  _ConsolePause
; Description....:  Pause and wait for any input
; Syntax.........:  _ConsolePause([$sPrompt = "Press any key to continue . . . "])
; Parameters.....:  $sPrompt - [Optional] Prompt text to display
;
; Return values..:  Success - Input string
;                   Failure - Empty string
; Author.........:  Erik Pilsits
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _ConsolePause($sPrompt = "Press any key to continue . . . ")
    Return _ConsoleGetInput($sPrompt, 1, True, "", "", True)
EndFunc

; #FUNCTION# ====================================================================================================
; Name...........:  _ConsoleRun
; Description....:  Run a command in the console window
; Syntax.........:  _ConsoleRun($sCmd[, $fWait = True[, $fNew = False[, $iShow = Default]]])
; Parameters.....:  $sCmd   - Command to run
;                   $fWait  - [Optional] Wait for command to finish
;                   $fNew   - [Optional] Run in new console window
;                   $iShow  - [Optional] Show flag (default for Run(Wait) is @SW_HIDE)
;
; Return values..:  Success - See Run(Wait) functions
;                   Failure - See Run(Wait) functions
; Author.........:  Erik Pilsits
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _ConsoleRun($sCmd, $fWait = True, $fNew = False, $iShow = Default)
    Local $iFlag = 0x10
    If $fNew Then $iFlag = 0x10000
    If $fWait Then
        Return RunWait($sCmd, "", $iShow, $iFlag)
    Else
        Return Run($sCmd, "", $iShow, $iFlag)
    EndIf
EndFunc







Global $name = _ConsoleGetInput("Type your name: ")
ConsoleWrite(@CRLF)
Global $pass = _ConsoleGetInput("Now something secret: ", 0, False, "", "", True, "*")
ConsoleWrite(@CRLF & @CRLF)
Global $inp = _ConsoleGetInput("Do you want to print your input? [y/n] ", 1, True, "(?i)[yn]")
ConsoleWrite(@CRLF)
If $inp = "y" Then
    ConsoleWrite("Your name: " & $name & @CRLF)
    ConsoleWrite("Your secret (not really): " & $pass & @CRLF)
EndIf
ConsoleWrite(@CRLF)
_ConsolePause("Press something to quit...")
Mola; veréis si ejecutáis el código, que lo segundo que escribáis no se verá, porque se muestran asteriscos ;)

Seguro que con las APIs de la consola pueden hacerse cosas muy chulas.

Yo de momento, el color, el título de la ventana y el prompt lo cambio ejecutando la línea de comandos antes de nada, con RUNWait() y oculto.

Si alguien sabe como hacerlo mediante APIs, o como modificar otros comportamientos de la consola con el API, me gustaría ver ejemplos, o links de la documentación

Salu2!

Re: Leer comandos del usuario en la consola

Publicado: 16 Nov 2017, 13:20
por Jonny
Al final tenía por el ordenador la UDF de consola de la que hablaba en el post anterior, así que os la paso por si a alguien le sirve.

Como decía, a mi me interesa más que nada por la función Cout(): la función Cin() no me funcionó, y Getch() no la probé; igual hasta usa la misma API que la función que os puse en el post anterior (creo que no). Pero sinceramente no la he probado. Sólo he visto que también usa un API de Windows.

Por lo que explicaba en el mensaje anterior, la librería creo que podría hacerse de otra forma. Ahora que me he parado a analizar un poco el código, lo de crear una consola ... En realidad, inicializa punteros, handles ETC necesarios.
vaya, que es más bien un "__Console__StartUP()" que "__Console__Create()" :)

Y en vez de comprobar en cada función, si se ha inicializado la UDF, debería de ser necesario hacerlo en el programa y listo.

Además, tiene una función "__Console__StartUP()", que despista, porque según la descripción de la función, veréis que no es para inicializar la UDF.

A mi no me queda claro que haya que usarla obligatoriamente antes de cualquier otra función; tendré que probarlo.

Aquí tenéis la UDF. Creo que puede mejorarse, si alguien tiene ganas. Si no, yo por el momento la usaré así, e igual cualquier día, me pongo a estudiarla bien, y modificar alguna cosilla.

Salu2!