Interactive hidden CMD window

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
julesverne
Posts: 42
Joined: 18 Apr 2017, 14:39
Contact:

Interactive hidden CMD window

19 May 2020, 02:53

Hi all, I've come back to this problem many times over the years. Some command line programs I use require a little bit of interactive behavior from the user. So trying to make this in a neat little GUI has always proved difficult.

Below is code that works to a point. It utilizes the new Win 10 command ssh to log into a server, request a password to be entered, run a linux command, and exit. For any testers I've made the cmd window unhidden so you can see it works if you test it on your own server, with the exception of course of the linux command I'm running. That you would need to change to whatever you want.

Code: Select all

InputBox, server, Server Information, Enter either the server name or IP address
InputBox, username, Username, Enter your username
InputBox, password, Enter Password, (your input will be hidden), hide
sshcommand = ssh %username%@%server%
Run, %comspec% /k %sshcommand%,,Show, sshpid
IfWinExist, ahk_pid %sshpid%, , ,
{
	ConsoleSend(password . "`r","ahk_pid " . sshpid)
}
sleep, 5000
;command below will output to command window but not to a variable or a msgbox.
ConsoleSend("dash retrieval ""General='Folder' and (start>now() OR last>now()) and (start<'2020-06-01' OR last<'2020-06-01')""`r", "ahk_pid " . sshpid)
sleep, 3000
ConsoleSend("exit`r")
Sleep, 2000
ConsoleSend("exit`r")
ExitApp
; Sends text to a console's input stream. WinTitle may specify any window in
; the target process. Since each process may be attached to only one console,
; ConsoleSend fails if the script is already attached to a console.
;Created by lexikos at the link below
;https://autohotkey.com/board/topic/25446-consolesend/
ConsoleSend(text, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="")
{
    WinGet, pid, PID, %WinTitle%, %WinText%, %ExcludeTitle%, %ExcludeText%
    if !pid
        return false, ErrorLevel:="window"
    ; Attach to the console belonging to %WinTitle%'s process.
    if !DllCall("AttachConsole", "uint", pid)
        return false, ErrorLevel:="AttachConsole"
    hConIn := DllCall("CreateFile", "str", "CONIN$", "uint", 0xC0000000
                , "uint", 0x3, "uint", 0, "uint", 0x3, "uint", 0, "uint", 0)
    if hConIn = -1
        return false, ErrorLevel:="CreateFile"
    
    VarSetCapacity(ir, 24, 0)       ; ir := new INPUT_RECORD
    NumPut(1, ir, 0, "UShort")      ; ir.EventType := KEY_EVENT
    NumPut(1, ir, 8, "UShort")      ; ir.KeyEvent.wRepeatCount := 1
    ; wVirtualKeyCode, wVirtualScanCode and dwControlKeyState are not needed,
    ; so are left at the default value of zero.
    
    Loop, Parse, text ; for each character in text
    {
        NumPut(Asc(A_LoopField), ir, 14, "UShort")
        
        NumPut(true, ir, 4, "Int")  ; ir.KeyEvent.bKeyDown := true
        gosub ConsoleSendWrite
        
        NumPut(false, ir, 4, "Int") ; ir.KeyEvent.bKeyDown := false
        gosub ConsoleSendWrite
    }
    gosub ConsoleSendCleanup
    return true
    
    ConsoleSendWrite:
        if ! DllCall("WriteConsoleInput", "uint", hconin, "uint", &ir, "uint", 1, "uint*", 0)
        {
            gosub ConsoleSendCleanup
            return false, ErrorLevel:="WriteConsoleInput"
        }
    return
    
    ConsoleSendCleanup:
        if (hConIn!="" && hConIn!=-1)
            DllCall("CloseHandle", "uint", hConIn)
        ; Detach from %WinTitle%'s console.
        DllCall("FreeConsole")
    return
}
So, here's what I really need. I've put in a comment in my code above that shows that the output from the linux command only displays to the terminal and not to a variable or a msgbox. Ideally I would like it to be as a variable so as to be able to create a GUI with the info. Can I get this into a variable?

In the past I've worked around this problem by using plink to log into the server using a bat script or ahk however the problem with plink is that some of the linux command lines are heavy with parenthesis and double and single quotes, and so they often fail because there are too many characters to escape and it's difficult to tell which characters are causing the problems, especially on the cmd line. As you can see from the command I've got in my code it's a lot of parenthesis and double and single quotes.

Code: Select all

"dash retrieval ""General='Folder' and (start>now() OR last>now()) and (start<'2020-06-01' OR last<'2020-06-01')""`r"
I've also tried the last two examples on the Run Command in the ahk Docs to be able to get the output into a variable, but because the same cmd window needs to be interactive with the user, RunCommand or RunManyCommands won't work. Unless you can somehow add a Stdin inbetween the StdOut commands. So the basic idea would be

Code: Select all

 #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
InputBox, server, Server Information, Enter either the server name or IP address
InputBox, username, Username, Enter your username
InputBox, password, Enter Password, (your input will be hidden), hide
sshcommand = ssh %username%@%server%
querycommand := "dash retrieval ""General='Folder' and (start>now() OR last>now()) and (start<'2020-06-01' OR last<'2020-06-01')""`r"

MsgBox % RunWaitMany(sshcommand, password, querycommand)


RunWaitMany(initialcommand, pass, command){
	shell := ComObjCreate("WScript.Shell")
    ; Open cmd.exe with echoing of commands disabled
    exec := shell.Exec(ComSpec " /Q /K " initialcommand)
    ; Send the commands to execute, separated by newline
	sleep 5000
  ;exec.StdIn.WriteLine(pass "`nexit")
    ;wait for server to accept credentials
    sleep, 3000
    exec.StdIn.WriteLine(command "`nexit")
    ; Read and return the output of all commands
	exec.StdIn.WriteLine("exit`r")
    return exec.StdOut.ReadAll()
}
The above code doesn't work. I modified the parameters of the RunWait Doc example here so I could I could make the first command the ssh command rather than "Echo Off" in the doc example. Secondly, the password is never sent to the cmd window. The user ends up having to enter in the password manually into the cmd window. After user has entered correct password. Cursor just sits there and blinks until you kill the script. Lastly, this code shows the cmd window which isn't what I want. I want it hidden.

Thanks in advance for all your help! xoxo jules
BNOLI
Posts: 548
Joined: 23 Mar 2020, 03:55

Re: Interactive hidden CMD window

19 May 2020, 10:07

Have you already checked the forum for :arrow: StdOutToVar()* (or similar functions/classes)?? Regarding the confusing appearance if there's an orgy of parentheses and other kryptonic stuff while setting up a valid command line, what about using a continuation section (during its setup) to split it in 'easier to read'-sections??

Good luck :)

* see its last posting for the 64bit release!
Remember to use [code]CODE[/code]-tags for your multi-line scripts. Stay safe, stay inside, and remember washing your hands for 20 sec !
julesverne
Posts: 42
Joined: 18 Apr 2017, 14:39
Contact:

Re: Interactive hidden CMD window

19 May 2020, 14:32

I looked at a modified code by @Segalion from that forurm where they were able to add stdin as well but didn't work for me.

Code: Select all

li_stdout(chars="",codepage="") {
	global hStdOutRd
    if (codepage="")
         codepage:=A_FileEncoding
    fout:=FileOpen(hStdOutRd, "h", codepage)
    if (IsObject(fout) and fout.AtEOF=0)
      return fout.Read()
   return ""
}

cli_stdin(sInput="",codepage="") {
   global  hStdInWr
    if (codepage="")
         codepage:=A_FileEncoding 
      If   sInput <>
      FileOpen(hStdInWr, "h", codepage).Write(sInput)
}

cli_close() {
	global  hStdInWr, hStdOutRd
	DllCall("CloseHandle","Ptr",hStdInWr)
	DllCall("CloseHandle","Ptr",hStdOutRd)
}

cli_createprocess(sCmd, sDir="")
{
   global  hStdInWr, hStdOutRd
   
   DllCall("CreatePipe","Ptr*",hStdInRd,"Ptr*",hStdInWr,"Uint",0,"Uint",0)
   DllCall("CreatePipe","Ptr*",hStdOutRd,"Ptr*",hStdOutWr,"Uint",0,"Uint",0)
   DllCall("SetHandleInformation","Ptr",hStdInRd,"Uint",1,"Uint",1)
   DllCall("SetHandleInformation","Ptr",hStdOutWr,"Uint",1,"Uint",1)
   if A_PtrSize=4
      {
      VarSetCapacity(pi, 16, 0)
      sisize:=VarSetCapacity(si,68,0)
      NumPut(sisize,    si,  0, "UInt")
      NumPut(0x100,     si, 44, "UInt")
      NumPut(hStdInRd , si, 56, "Ptr")
      NumPut(hStdOutWr, si, 60, "Ptr")
      NumPut(hStdOutWr, si, 64, "Ptr")
      }
   else if A_PtrSize=8
      {
      VarSetCapacity(pi, 24, 0)
      sisize:=VarSetCapacity(si,96,0)
      NumPut(sisize,    si,  0, "UInt")
      NumPut(0x100,     si, 60, "UInt")
      NumPut(hStdInRd , si, 80, "Ptr")
      NumPut(hStdOutWr, si, 88, "Ptr")
      NumPut(hStdOutWr, si, 96, "Ptr")
      }

   DllCall("CreateProcess", "Uint", 0, "Ptr", &sCmd, "Uint", 0, "Uint", 0, "Int", True, "Uint", 0x08000000, "Uint", 0, "Ptr", sDir ? &sDir : 0, "Ptr", &si, "Ptr", &pi)
   DllCall("CloseHandle","Ptr",NumGet(pi,0))
   DllCall("CloseHandle","Ptr",NumGet(pi,A_PtrSize))
   DllCall("CloseHandle","Ptr",hStdOutWr)
   DllCall("CloseHandle","Ptr",hStdInRd)
}

MySimpleTest:
InputBox, server, Server Information, Enter either the server name or IP address
InputBox, username, Username, Enter your username
InputBox, password, Enter Password, (your input will be hidden), hide
FileEncoding, CP850
cli_createprocess("ssh " . userid . "@" . server)
sleep 3000
cli_stdin(password . "`r`n")
sleep 5000
cli_stdin("echo hello`r`n")
sleep 1000
out:=cli_stdout()
msgbox,, TEST SIMPLE LINUX COMMAND OF ECHO:, %out%
cli_stdin("quit`r`n")
sleep 500
cli_stdin("exit`r`n")
cli_close()
ExitApp

OriginalExamplebySegalion:
FileEncoding, CP850
cli_createprocess("netsh.exe")
sleep 300
cli_stdin("firewall`r`n")
sleep 100
cli_stdin("show config`r`n")
sleep 1000
out:=cli_stdout()
msgbox,, FIREWALL CONFIGURATION:, %out%
cli_stdin("bye`r`n")
cli_close()
Return
Even with a simple linux echo command the msgbox is still empty.
BoBo
Posts: 6564
Joined: 13 May 2014, 17:15

Re: Interactive hidden CMD window

19 May 2020, 15:25

My Linux experience is close to nothing, but isn't it correct that Linux/UNIX is using only "`r" as EOL char? So why use it differently in 'MySimpleTest' ?
julesverne
Posts: 42
Joined: 18 Apr 2017, 14:39
Contact:

Re: Interactive hidden CMD window

19 May 2020, 15:54

Thanks for the reply @BoBo unfortunately that didn't help. Was a good suggestion though, because that is true about linux.

I do love the fact that the cmd window is hidden but for debugging it's a bit difficult to see what's happening. Does someone know how to show the CMD window in this code from my last response for debugging purposes? Perhaps that could help figure out this problem.
BoBo
Posts: 6564
Joined: 13 May 2014, 17:15

Re: Interactive hidden CMD window

20 May 2020, 00:17

Maybe this helps if tweaked a bit (eg to run .sh - scripts instead of cmd-lines. StdOut switched off if the Wait param =false)?
ExecScript - Execute a script with parameters: https://www.autohotkey.com/boards/viewtopic.php?p=217626#p217626 (by @swagfag)
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

20 May 2020, 01:12

I created a class just for this: CLI - Swiss Army Knife.

Lots of examples included to capture and interact.

Let me know if you have difficulty using this.
BNOLI
Posts: 548
Joined: 23 Mar 2020, 03:55

Re: Interactive hidden CMD window

20 May 2020, 01:40

TheArkive wrote:
20 May 2020, 01:12
I created a class just for this: CLI - Swiss Army Knife.

Lots of examples included to capture and interact.

Let me know if you have difficulty using this.
I've seen your class, but haven't seen (while I'm sure it's there) the explicitly requested option (see above) to switch off the stealth-mode for debugging? Would you mind pointing out where to find that, or provide a sample command line with its parameter to show how to accomplish that? Thx a lot :)
Remember to use [code]CODE[/code]-tags for your multi-line scripts. Stay safe, stay inside, and remember washing your hands for 20 sec !
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

20 May 2020, 02:31

BNOLI wrote:
20 May 2020, 01:40
I've seen your class, but haven't seen (while I'm sure it's there) the explicitly requested option (see above) to switch off the stealth-mode for debugging? Would you mind pointing out where to find that, or provide a sample command line with its parameter to show how to accomplish that? Thx a lot :)
Sure thing, I could compose a more direct example. First an explanation.

You can't show the console with the given function the way it's being used. The cli_createprocess() function is initializing the STARTUPINFO structure with 0x100 (STARTF_USESTDHANDLES) on line 38 and 48 ... which does allow you to tap into StdIn and StdOut, but it does NOT create a console window. So there is no window to show. Even if you were to use 0x101 (which would create a console window) you wouldn't have the handle to that window, or the PID of the process, with the code as it is, and finding it, especially if you have multiple background CLI windows running, could be tricky.

You should be able to extract the PID using this on line 55 (move line 55 down and insert):
pid := NumGet(pi, A_PtrSize*2, "uint")

... but this should only be done if the result of line 54 is non-zero, indicating success, so that result should be captured into a var (var := DllCall("CreateProcess",...)). If that value is zero, then the whole function should abort.

If you setup my library and examples as-is, there are Show Window and Hide Window buttons, so you can toggle showing the console window on-the-fly. Basically, once you create a var using the class, the .pid property will allow you to show the window with WinShow, % "ahk_pid " cli.pid easily.

I'll post again once I've managed to compose a short example for this thread.
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

20 May 2020, 03:10

Sorry one more thing...

If you are using 0x101 to capture the streams manually and create a window, then you can't actually see the output to the console when you show the window, because you are tapping into StdOut and StdErr directly. That's one of the reasons I created mode m in my class. But mode m is meant for capturing animations on the command line, like progress bars or incrementing percent.

So ... examples 5 and 7 in my example script keep the cli process active and are therefore interactive. So you can see all the command line output, except for animations (like incrementing percent). This should suffice for debugging.

I'm afraid your request sounds simple, but it's actually much more complex than that. You can't "debug on the original console" and tap into StdOut, unless you bother to actually copy all StdOut data to the console after you create the console, and that is not as easy as it sounds. What kind of debugging are you trying to do? If all you need is to see StdOut, then you can already see that with the function you are using.

This will help, replace line 46 with this: sisize:=VarSetCapacity(si,104,0).

Initializing si as only 96 bytes cuts off the StdErr handle. I had used @segalion's function as a base to build my class library and had to overcome this to actually get StdOut and StdErr together, which is the default behavior. Of course that line only affects 64-bit systems.

There is lots more to say on this subject, but I need to know further questions first ;-) ... let me know what your next question is.
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

20 May 2020, 03:28

In case this helps to illustrate, here is a short example script with my class, but when you show the window ... you won't see anything, because that's how StdOut / consoles work when you disconnect StdOut from the console and handle it yourself.

Code: Select all

#INCLUDE TheArkive_CliSAK.ahk
Global c

c := New cli("cmd dir","mode:s|showWindow:1")
return

F10:: ; hide window
	WinHide, % "ahk_pid " c.pid
return

F11:: ; show window
	WinShow, % "ahk_pid " c.pid
return

F12::
	c.Close()
	ExitApp
return
Just make sure you #INCLUDE my library for this example to work.

===================================================================
EDIT: In case anyone is wondering why I allow my CLISAK class to create a console window that doesn't show anything, it is because I need a way to terminate command line programs cleanly.

CTRL+Break and CTRL+C need to be received by a window. Without a window, you will be forced to use the KILL command, or one of the other built-in AHK commands, none of which are a guarantee to be able to terminate certain command line applications.

In my class library, you can use obj.CtrlBreak() or obj.CtrlC() to send the CTRL+Break / CTRL+C signals to terminate a command line application that accepts them.

Once again, using mode "m", in my class library, you can actually have a console window that shows output, but the data is read (or more accurately ... scraped) about every 10ms, so it is good for capturing animations, but NOT for complete output of StdOut.
julesverne
Posts: 42
Joined: 18 Apr 2017, 14:39
Contact:

Re: Interactive hidden CMD window

20 May 2020, 16:47

@TheArkive THIS IS WHAT I'VE BEEN LOOKING FOR!!! So here's the thing, before I try your examples here, I downloaded your code an hour ago. Ran the example from the forum and immediately got the runtime error below:
---------------------------
TheArkive_CliSAK_Example.ahk
---------------------------
Error at line 683 in #include file "D:\Documents\TheArkive_MsgBox2.ahk".

Line Text: WinSetEnabled 0, "ahk_id " this.hParent
Error: This line does not contain a recognized action.

The program will exit.
---------------------------
OK
---------------------------
I noticed on GIT you updated 10 hours ago Msgbox2, wonder if this is a bug from the latest commit. I also tried running TheArkive_CliSAK_Example_Messages.ahk and the script flashed right away and immediately closed. Am i doing something wrong with regards to these examples?

Regardless, this looks to be EXACTLY what I've been looking for, literally for years!! Big ups!!
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

21 May 2020, 00:55

---------------------------
TheArkive_CliSAK_Example.ahk
---------------------------
Error at line 683 in #include file "D:\Documents\TheArkive_MsgBox2.ahk".

Line Text: WinSetEnabled 0, "ahk_id " this.hParent
Error: This line does not contain a recognized action.

The program will exit.
---------------------------
OK
---------------------------
Looks like you downloaded the AHK2 version. You need the AHK1 version.
julesverne wrote:
20 May 2020, 16:47
@TheArkive THIS IS WHAT I'VE BEEN LOOKING FOR!!!
Glad to help! Hopefully we can get you setup with the right version.

EDIT: I just tried downloading and testing to see if I got the uploaded versions mixed up. They are working fine. AHK1 folder is for AHK v1.1.32.00, which is what I assume you are using. AHK2 folder is for AHK v2.0-a108-H021, latest alpha build.
julesverne
Posts: 42
Joined: 18 Apr 2017, 14:39
Contact:

Re: Interactive hidden CMD window

21 May 2020, 05:55

Hi @TheArkive So first off my apologies for overlooking that big mistake. I copied the correct msgbox2 and it's working fine now. Your Example is incredibly thorough. I have to admit even after seeing it in action, I'm a bit intimidated on figuring out how to use this to get what I need. I did try using ssh (new Win 10 cmd option) into my linux server with the TheArkive_CliSAK_Example.ahk GUI with Example 7 and unfortunately got this error message in the GUI command output:

Code: Select all

StdErr:
Psuedo-terminal will not be allocated because stdin is not a terminal
Interestingly however, plink (3rd party ssh) had no problem being interactive with the linux server in Example 7 of TheArkive_CliSAK_Example.ahk. Even more interestingly is that StdErr were the messages I was seeing in GUI command output. Not stdin or stdout.

Code: Select all

StdErr:
Using username "xxxxx".
===============================
| Password:
===============================
StdErr:
Keyboard-interactive authentication prompts from server:
===============================
StdErr:
End of keyboard-interactive prompts for server
===============================
Obviously, I was just curious to see how this works before rushing into development. To be honest however after running the examples and reading through the different files, I'm a bit intimidated by this code, even with the provided examples, at least in terms of how to apply it to my problem.
Below is the basic layout I came up with based on your example. I made comments on lines immediately before the command if I was unsure of what I was doing.

Code: Select all

; AHK v1
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

#INCLUDE %A_ScriptDir%
#INCLUDE TheArkive_CliSAK.ahk
;#INCLUDE TheArkive_CliSAK_Example_Messages.ahk
;#INCLUDE TheArkive_MsgBox2.ahk

InputBox, server, Server Information, Enter either the server name or IP address
InputBox, username, Username, Enter your username
InputBox, password, Enter Password, (your input will be hidden), hide
sshlogin := "ssh " . username . "@" . server
sshcmd1 = dash retrieval "General='Folder' and (start>now() OR last>now()) and (start<'2020-06-01' OR last<'2020-06-01')"

c := new cli("cmd /c " . sshlogin,"mode:cs|ID:Console")

c.mode .= "oeip"

c.runCmd()

;based on the tests with TheArkive_CliSAK_Example.ahk I believe ssh output is sent to stdErr
stdErr := c.error

; wait for ssh password request (less than 10 sec)
; i'm guessing there is an efficient way to discover when it's ready rather than a static 10 second sleep
sleep, 10000 

; send password var from line 14
c.write(password)

; wait for ssh connection successful login (less than 10 sec)
; i'm guessing their is an efficient way to known when it's ready rather than a static 10 second sleep
sleep, 10000

; send sshcmd1 var
c.write(sshcmd1)

; capture output from sshcmd1 into var
; based on the tests with TheArkive_CliSAK_Example.ahk I believe ssh output is sent to stdErr
stdErr := c.error

; create command to server based on output from previous command
newcommand := strsplit(stdErr, ":")

; send new command to server
; capture output from command into var
stdErr := c.write(newcommand)

; send exit command to logout from server
c.write("exit")

; close cmd window session
c.close()
ExitApp



; ============================================================================
; Callback Functions
; ============================================================================
stdOutCallback(data,ID) { ; stdout callback function --- default: stdOutCallback()
	If (ID = "Console") {
		AppendText(CmdOutputHwnd,data)
	} Else If (ID = "modeM") {
		lastLine := GetLastLine(data)
		
		; use only one of these, comment out the other...
		; ======================================================
		GuiControl, , %CmdOutputHwnd%, %lastLine%	; use the GetLastLine() function
		; GuiControl, , %CmdOutputHwnd%, %data%		; display all the data
	}
}

stdErrCallback(data,ID) { ; stdErr callback function --- default: stdErrCallback()
	If (ID = "Console") { ; type some bad commands in Example #7 to see how this works
		msg := "`r`n=============================================`r`n"
			 . "StdErr:`r`n" data "`r`n"
			 . "=============================================`r`n`r`n"
		AppendText(CmdOutputHwnd,msg) ; handle StdErr differently
	}
}

cliPromptCallback(prompt,ID) { ; cliPrompt callback function --- default: cliPromptCallback()
	Gui, Cmd:Default ; need to set GUI as default if NOT using control HWND...
	GuiControl, , CmdPrompt, ========> new prompt =======> %prompt% ; set Text control to custom prompt
}
; ============================================================================
; send command to CLI instance when user presses ENTER
; ============================================================================

OnMessage(0x0100,"WM_KEYDOWN") ; WM_KEYDOWN
WM_KEYDOWN(wParam, lParam, msg, hwnd) { ; wParam = keycode in decimal | 13 = Enter | 32 = space
    CtrlHwnd := "0x" Format("{:x}",hwnd) ; control hwnd formatted to match +HwndVarName
    If (CtrlHwnd = CmdInputHwnd And wParam = 13) ; ENTER in App List Filter
		SetTimer, SendCmd, -10 ; this ensures cmd is sent and control is cleared
}

SendCmd() { ; timer label from WM_KEYDOWN
	Gui, Cmd:Default ; give GUI the focus / required by timer(s)
	GuiControlGet, CmdInput ; get cmd
	c.write(CmdInput) ; send cmd
	Gui, Cmd:Default
	GuiControl, , CmdInput ; clear control
	GuiControl, Focus, CmdInput ; put focus on control again
}

; ================================================================================
; ================================================================================
; support functions
; ================================================================================
; ================================================================================

; ================================================================================
; AppendText(hEdit, ptrText)
; example: AppendText(ctlHwnd, &varText)
; Posted by TheGood:
; https://autohotkey.com/board/topic/52441-append-text-to-an-edit-control/#entry328342
; ================================================================================
AppendText(hEdit, sInput, loc="bottom") {
    SendMessage, 0x000E, 0, 0,, ahk_id %hEdit%						;WM_GETTEXTLENGTH
	If (loc = "bottom")
		SendMessage, 0x00B1, ErrorLevel, ErrorLevel,, ahk_id %hEdit%	;EM_SETSEL
	Else If (loc = "top")
		SendMessage, 0x00B1, 0, 0,, ahk_id %hEdit%
    SendMessage, 0x00C2, False, &sInput,, ahk_id %hEdit%			;EM_REPLACESEL
}

; ================================================================================
; hotkeys
; ================================================================================

#IfWinActive, ahk_class AutoHotkeyGUI
^c::c.ctrlC()
^CtrlBreak::c.CtrlBreak()
^b::c.CtrlBreak()			; in case user doesn't have BREAK key
^x::c.close()				; closes active CLi instance if idle
Thanks for any help.
Jules.
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

21 May 2020, 06:55

@julesverne

EDIT4: Just looked at your code. Sorry for changing this reply so many times :-P ... I'm waiting on pins and needles to hear from my wife to pick her up from an appointment, so I'm not sure when I'll get called away.

Your code looks good and I don't see any major issues, except that the SSH command doesn't allow StdOut to be disconnected from the terminal window. So you'll be forced to use mode "m" for the time being, which i wouldn't recommend.

I was taking a look at your previous posts and I realized that how you placed the quotes seems possibly excessive. In my library, you don't need to add `r because `r`n is already added, but if that ends up being an issue of course I'll have to add an option to change that.

You usage of quotes looks like you are using the Run command on AHK, which is DEFINITELY not the same as what I would call "the normal command". It's close but not quite. With my script, you can type things as they need to be typed directly on the command line.

So my first suggestion is go back to plink, and try generating your command strings as if you were actually typing in a cmd window. I apologize if I'm not fully understanding or getting something wrong (that may be simple and fundamental). I don't do much with SSH so I'll have to dig into it to see how my library handles it. Still enroute to setting up an SSH server...
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

21 May 2020, 09:44

Just wanted to update my progress here ... I have an SSH server setup, and I'm messing around with it. I'll start with using plink to try and get a grasp on the commands you are trying to use and to see what is really necessary in regards to nesting parameters with quotes and such...

I'll take your latest script with my class as a base, and I'll tweak it from there ... once I feel like i got something good according to what your latest post shows (and I'll refer to your other posts to for context), then I'll post my results.

EDIT:

I have good news and bad news. The good news is that example #7 in my example script works nicely as an interactive console with plink ... the bad news is that the control codes are a bit crazy ... I'll have to add some exceptions to try and detect a linux shell and compensate for the existence of control codes.

So if you run plink using example #7 you'll see it works, but it's not very readable. I'll be working on some fixes tonight to see if I can get this working as intended.

The funny thing is that I can handle an android environment no problem, but a legit linux environment throws many more control codes so I'll have to include ways to properly handle these control codes.

EDIT:

the sanitize options with plink don't sanitize enough ... it helps a bit but still gotta figure out how to handle the rest of the incoming data
julesverne
Posts: 42
Joined: 18 Apr 2017, 14:39
Contact:

Re: Interactive hidden CMD window

21 May 2020, 10:40

EDIT4: Just looked at your code. Sorry for changing this reply so many times :-P ... I'm waiting on pins and needles to hear from my wife to pick her up from an appointment, so I'm not sure when I'll get called away.
not a problem AT ALL. I appreciate your help.
TheArkive wrote:
21 May 2020, 09:44
Just wanted to update my progress here ... I have an SSH server setup, and I'm messing around with it. I'll start with using plink to try and get a grasp on the commands you are trying to use and to see what is really necessary in regards to nesting parameters with quotes and such...

I'll take your latest script with my class as a base, and I'll tweak it from there ... once I feel like i got something good according to what your latest post shows (and I'll refer to your other posts to for context), then I'll post my results.
cool! Just to be clear, the sshcmd1 var in my code from my last post was just an example of:
  • 1. the kind of crazy, quoted, double quoted, escaped strings I have to use A LOT so my hope with this script initially was to never have to think about that. Your class lib seems like a hidden CLI that I could create a pretty ahk wrapper around. Which again I've tried to create over the years without success and had to rely on 3rd party CLI apps (plink) when was thinking now that ssh is part of the OS it would be great to revisit this without 3rd party app.
  • 2. is a private command and not something available in linux distros for you to be able to test with. However, I think your class would be able to handle the command, but it's really just making that initial ssh connection to be able to log into the server.

thanks again for looking into this, your class is the closest thing I've seen to create an interactive (but hidden) CLI, that at the very least works with plink out of the box, but ssh is my endgame.
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

21 May 2020, 18:01

Just so we can share resources, here's a link to all the garbled text:

http://adoxa.altervista.org/ansicon/sequences.txt

This should help to figure out some of the weirdness.
User avatar
TheArkive
Posts: 1030
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: Interactive hidden CMD window

22 May 2020, 05:52

I have an Ubuntu machine, and I'm trying to set it up so I can further troubleshoot stuff with this class.

I should be able to accomplish quite a bit with just Ubuntu (i should think). And eventually i will get around to installing those distros and testing them out too.

In my library, streaming mode 's" is much more robust with the ability to detect the prompt, which is a signal that the last run command is complete. I've noticed a significant variation of terminal prompts and I need to code that in so that the prompt callback can function properly for mode "s" and mode "b". Actually mode "b" is broken without the ability to detect the prompt.

I'll post my progress as I'm able to push things forward. Mostly I need to be able to see the output in a redirected text file when using the ssh user@login > test.txt command, which i can't right now for some reason. I think my windows setup ssh server isn't exactly working as intended, since I'm connecting to a windows environment instead of a linux environment. I'm really trying to avoid modifying mode "m" for this task since the performance of that approach will pretty much be in the toilet by comparison.

Edit: finally have Ubuntu setup on virtual machine. Running some more tests to finish up the filters to clean up the control codes, and then i can start working on a few ways to improve ssh command support. I can finally see the output when redirecting > to text file. So this should be a decent / addition, although such a method is technically a security risk by comparison.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: apeironn, madensuyu1, peter_ahk and 358 guests