Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

ConsoleSend


  • Please log in to reply
19 replies to this topic
Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
; 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.
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
}
Example:
ConsoleSend("Hooray, it works!", "ahk_class ConsoleWindowClass")
The main advantage of this over ControlSend is explained by the help file:

By default, modifier keystrokes (Control, Alt, Shift, and Win) are sent as they normally would be by the Send command. This allows command prompt and other console windows to properly detect uppercase letters, control characters, etc. It may also improve reliability in other ways.

However, in some cases these modifier events may interfere with the active window, especially if the user is actively typing during a ControlSend or if the Alt key is being sent (since Alt activates the active window's menu bar).

Currently ConsoleSend accepts literal text only. Adapting it to send unicode characters or control characters is a possibility.

It seems that `r should be used in place of `n or {Enter}.

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
I must be missing something... wouldn't ControlSendRaw or {Raw} do the same?

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Read the quote. ContrlSend-ing {modifier up/down} does not work for console windows. It is probably also a solution for [I try to ControlSend " to cmd. It sends Ä], since it sends character codes, not key codes.

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
Interesting.
Maybe autohotkey should be built as a console application, that happens to also have some windows.
Then maybe the standard streams will behave properly.

Anyways, thanks for this function.
I used this function on the rosetta code task for user output.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
If AutoHotkey is built as a console application, a console will appear whenever a script is launched. In 99.999% of cases that would be bad. Also, the standard streams already behave exactly as they're supposed to - they're just not associated with the console by default.

If 'the goal is to display the string "Goodbye, World!" on a text console', the following may be more appropriate:
DllCall("AllocConsole")
FileAppend, Goodbye`, World!, CONOUT$
FileReadLine, _, CONIN$, 1
If you want to output to the console of the process which launched the script, you can use AttachConsole instead of AllocConsole. AttachConsole accepts the PID of any process which has a console. (-1 is a special value indicating the parent process.) The only problem with this is that cmd.exe won't necessarily wait for the script to end before showing a prompt etc.:
DllCall("AttachConsole", "int", -1)
FileAppend, Goodbye`, World!, CONOUT$
IMO your example makes AutoHotkey look cumbersome compared to most of the other examples. Not all of the examples on that page output to console, so I think it would be appropriate to post an (additional) example which reflects the purpose of AutoHotkey:
SendInput Goodbye, World{!}


  • Guests
  • Last active:
  • Joined: --
How to consolesend the 'enter key' ?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
It's either "`r" (carriage-return) or "`n" (newline), I'm not sure which.

MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009

DllCall("AttachConsole", "int", -1)
FileAppend, Goodbye`, World!, CONOUT$


I have a command line file copy routine and was looking to output to console if run from the command line as opposed to a shortcut. The above method is cleaner than my kludge of using Send with a string using echo command to avoid "x file(s) copied" is not a command error.

But I couldn't figure out how to get rid of the hanging cursor in the command prompt. FileAppend with `n or {Enter} did not jar the cursor back to a prompt. I also tried sending control z, control m etc.. The cursor would move down a line, but not give me the prompt back.

In the end I used a hybrid approach

if DllCall("AttachConsole", "int", -1)
{
 CopyMsg := CopyCount . " File(s) Copied `n"
 FileAppend, %CopyMsg%, CONOUT$
 WinActivate,"ahk_class ConsoleWindowClass"
 Send,{Enter}
 Exit
}
MsgBox, 4160, , %CopyCount% File(s) Copied, 3

If AttachConsole succeeds I assume the program was run from command prompt. Otherwise use MsgBox.

Just thought it may be useful. :)

"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


gregisoutofstep
  • Members
  • 2 posts
  • Last active: Apr 30 2014 05:51 PM
  • Joined: 30 Aug 2013

I tried many different combos involving using +x, {shift down}x{shift up} to send capital letters to a console window with ControlSend only to have it mess them up randomly if the window was active. After about a month of going back and forth with ControlSend and SendInput (works great, but the window has to be active), I finally found ConsoleSend that does exactly what I need.

 

Thanks!



garry
  • Spam Officer
  • 3219 posts
  • Last active: Sep 20 2018 02:47 PM
  • Joined: 19 Apr 2005

related

found a script from Lexikos 2009-07-02
http://www.autohotke...a-gui/?p=264010
and an example here
http://www.autohotke...-window-in-gui/

I tried script above :
 

run,%comspec% /k
sleep,2000
transform,s,chr,13  ; - add enter
F1:="dir" . s
ConsoleSend(F1, "ahk_class ConsoleWindowClass")
return



Guest10
  • Members
  • 1216 posts
  • Last active: Oct 30 2015 05:12 PM
  • Joined: 27 Oct 2012

@garry

 

i tried this and it runs great! is there a way to add a GUI so that i can select the directory/folder in advance before running this script so that i can get to that folder directly in advance and get the list in that directory?



Guest10
  • Members
  • 1216 posts
  • Last active: Oct 30 2015 05:12 PM
  • Joined: 27 Oct 2012

i created this version but i am not sure if it is very elegant although it does what it is intended to do! can this be improved?

FileSelectFolder, OutputVar, , 3
If OutputVar =
MsgBox, You didn't select a folder
Else
MsgBox, You selected folder "%OutputVar%"
FileCopy, C:\...\Garry_Console_Script.ahk, %OutputVar%
SetWorkingDir, %OutputVar%
#Include ConsoleSend.ahk

run,%comspec% /k
sleep,2000
transform,s,chr,13  ; - add enter
F1:="dir" . s
ConsoleSend(F1, "ahk_class ConsoleWindowClass")
FileDelete %OutputVar%\Garry_Console_Script.ahk
return


garry
  • Spam Officer
  • 3219 posts
  • Last active: Sep 20 2018 02:47 PM
  • Joined: 19 Apr 2005

don't understand really ...

maybe you'ld like to use this , send dos commands to a big  DOS-Window

click command at left border (listbox)

EDIT :

added a menu to change directory (Fileselectfolder)

;-------- saved at Donnerstag, 25. April 2013 19:12:26 --------------
;-------- http://www.autohotkey.com/board/topic/92644-show-cmd-window-in-gui/ ---
;-------- saved at 22:51:06 maandag april 22-04-2013 --------------
;-------- http://www.autohotkey.com/board/topic/42308-embedding-a-console-window-in-a-gui/#entry264010 ---
;-------- user Lexikos  Posted 02 July 2009 - 12:21 PM

#NoEnv              ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input      ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%
SetTitleMatchMode 2



;- Styles we want to remove from the console window:
WS_POPUP := 0x80000000
WS_CAPTION := 0xC00000
WS_THICKFRAME := 0x40000
WS_EX_CLIENTEDGE := 0x200
;- Styles we want to add to the console window:
WS_CHILD := 0x40000000
;- Styles we want to add to the Gui:
WS_CLIPCHILDREN := 0x2000000
;- Flags for SetWindowPos:
SWP_NOACTIVATE := 0x10
SWP_SHOWWINDOW := 0x40
SWP_NOSENDCHANGING := 0x400
;-----------------------------------------------------

; Create Gui and get window ID.
Gui,1:default
Gui, +LastFound +%WS_CLIPCHILDREN%
GuiWindow := WinExist()

Menu,S1,add,FolderSelect          ,MH0
menu,myMenuBar,Add,Change Directory   ,:S1
Gui,1:menu,MyMenuBar


transform,s,chr,07           ;-- bell

e4x=
(Ltrim Join`r`n
dir
ver
date /t
time /t
bell
)

  Gui,1: Color, Default, 000000
  Gui,1:Font,  S10 CDefault , FixedSys
  Gui,1:add,Listbox, cWhite  x5  y27   w155 h400 Sort vLB1 gLB

;- Launch hidden cmd.exe and store process ID in pid.
title1=QUIT with Escape
Run %COMSPEC% /k "title %title1% & mode con lines=50 cols=120",,hide,pid
;Run, %ComSpec% /k,, Hide, pid

;- Wait for console window to be created, store its ID.
DetectHiddenWindows, On
WinWait, ahk_pid %pid%
sleep,500
ConsoleWindow := WinExist()

;- Get size of console window, excluding caption and borders:
VarSetCapacity(ConsoleRect, 16)
DllCall("GetClientRect", "uint", ConsoleWindow, "uint", &ConsoleRect)
ConsoleWidth := NumGet(ConsoleRect, 8)
ConsoleHeight:= NumGet(ConsoleRect, 12)

;- Apply necessary style changes.
WinSet, Style, % -(WS_POPUP|WS_CAPTION|WS_THICKFRAME)
WinSet, Style, +%WS_CHILD%
WinSet, ExStyle, -%WS_EX_CLIENTEDGE%

;- Put the console into the Gui.
DllCall("SetParent", "uint", ConsoleWindow, "uint", GuiWindow)

;- Move and resize console window. Note that if SWP_NOSENDCHANGING
;- is omitted, it incorrectly readjusts the size of its client area.
DllCall("SetWindowPos", "uint", ConsoleWindow, "uint", 0
    , "int", 160, "int", 2, "int", ConsoleWidth, "int", ConsoleHeight
    , "uint", SWP_NOACTIVATE|SWP_SHOWWINDOW|SWP_NOSENDCHANGING)


;- Add a button below the console.
Gui, Add, Button, % "y" ConsoleHeight+20 , Exit
; Show the Gui. Specify width since auto-sizing won't account for the console.
ww:="W" ConsoleWidth+220
;Gui, Show, % "W" ConsoleWidth+220
Gui, Show, x100 y20 w%ww%

Loop, Parse, e4x, `n, `r
 {
 IfEqual,A_Loopfield,, Continue
 GuiControl,1:,LB1,%a_loopfield%
 }

; Be sure to close cmd.exe later.
OnExit, Exiting
return
;-----------------------------------------------

MH0:
FileSelectFolder, OutputVar, , 3
If OutputVar =
  return
dirc:=outputvar
ControlSend,%title1%,cd "%dirc%"`n,
return


;---------------------
lb:
Gui,1:submit,nohide
GuiControlGet,LB1
if (lb1="bell")
   lb1=echo %s%
ControlSend,%title1%,%lb1%`n,
return


;-------------------
GuiEscape:
GuiClose:
ButtonExit:
Exiting:
OnExit
Process, Close, %pid%    ; May be a bit forceful? No effect if it already closed.
Process, WaitClose, %pid%
ExitApp
;=============================================================




Guest10
  • Members
  • 1216 posts
  • Last active: Oct 30 2015 05:12 PM
  • Joined: 27 Oct 2012

@garry

 

basically, i try to avoid moving the script to the working directory (script directory) to get the list. i would like to get the list in ANY directory i select without moving the script into that directory. in my script above, i first move a copy of the script into that SELECTED directory and then delete it after getting the list. i thought there might be a better way without moving and deleting the script?



Guest10
  • Members
  • 1216 posts
  • Last active: Oct 30 2015 05:12 PM
  • Joined: 27 Oct 2012

since i also have issues with ControlSend, does this mean ConsoleSend is superior across the board over ControlSend in all instances?

I tried many different combos involving using +x, {shift down}x{shift up} to send capital letters to a console window with ControlSend only to have it mess them up randomly if the window was active. After about a month of going back and forth with ControlSend and SendInput (works great, but the window has to be active), I finally found ConsoleSend that does exactly what I need.

 

Thanks!