AutoHotKey: InputBox with multiline input - windows

In AutoHotKey, I want to have something like InputBox except that the text input is multiline. (i.e. like a textarea).
I want there to be two buttons, "Ok" and "Cancel", and I want them both to have accelerators. I want this code to be in the form of a function that I can call from other hotkeys to get multiline user input whenever I want. I want to be able to set the default text shown when the dialog is shown. I want the function to return null or empty string if the cancel button was pressed. I want the Esc key to cause the dialog to be closed as if the cancel button was pressed (and not exit the entire script). I want the dialog to show in the center of the screen, and to use the font that Windows usually uses for dialogs.

try this
!1::
MsgBox % MultiLineInputBox("Hello World:", "stuff, more stuff", "Custom Caption")
return
MultiLineInputBox(Text:="", Default:="", Caption:="Multi Line Input Box"){
static
ButtonOK:=ButtonCancel:= false
if !MultiLineInputBoxGui{
Gui, MultiLineInputBox: add, Text, r1 w600 , % Text
Gui, MultiLineInputBox: add, Edit, r10 w600 vMultiLineInputBox, % Default
Gui, MultiLineInputBox: add, Button, w60 gMultiLineInputBoxOK , &OK
Gui, MultiLineInputBox: add, Button, w60 x+10 gMultiLineInputBoxCancel, &Cancel
MultiLineInputBoxGui := true
}
GuiControl,MultiLineInputBox:, MultiLineInputBox, % Default
Gui, MultiLineInputBox: Show,, % Caption
SendMessage, 0xB1, 0, -1, Edit1, A
while !(ButtonOK||ButtonCancel)
continue
if ButtonCancel
return
Gui, MultiLineInputBox: Submit, NoHide
Gui, MultiLineInputBox: Cancel
return MultiLineInputBox
;----------------------
MultiLineInputBoxOK:
ButtonOK:= true
return
;----------------------
MultiLineInputBoxGuiEscape:
MultiLineInputBoxCancel:
ButtonCancel:= true
Gui, MultiLineInputBox: Cancel
return
}

You can keep it pretty short:
(tested and works)
MultiLineInput(Text:="Waiting for Input") {
Global MLI_Edit
Gui, Add, Edit, vMLI_Edit x2 y2 w396 r4
Gui, Add, Button, gMLI_OK x1 y63 w199 h30, &OK
Gui, Add, Button, gMLI_Cancel x200 y63 w199 h30, &Cancel
Gui, Show, h94 w400, %Text%
Goto, MLI_Wait
MLI_OK:
GuiControlGet, MLI_Edit
MLI_Cancel:
GuiEscape:
ReturnNow := True
MLI_Wait:
While (!ReturnNow)
Sleep, 100
Gui, Destroy
Return %MLI_Edit%
}
MsgBox % MultiLineInput("Tell me 5 things you like.")
This is what it could look like:
And here is what it returns printed in a MsgBox: Click

Updated version from answer https://stackoverflow.com/a/25800045/2043349 that fixes the bug that the Prompt Text won't be updated if you use the function multiple times:
MultiLineInputBox(Text:="", Default:="", Caption:="Multi Line Input Box")
{
static
ButtonOK:=ButtonCancel:= false
Gui GuiMLIB:New,, % Caption
Gui, add, Text, w600, % Text
Gui, add, Edit, r10 w600 vMLIBEdit, % Default
Gui, add, Button, w60 gMLIBOK , &OK
Gui, add, Button, w60 x+10 gMLIBCancel, &Cancel
Gui, Show
while !(ButtonOK||ButtonCancel)
continue
if ButtonCancel
return
Gui, Submit
return MLIBEdit
;----------------------
MLIBOK:
ButtonOK:= true
return
;----------------------
GuiMLIBGuiEscape:
GuiMLIBGuiClose:
MLIBCancel:
ButtonCancel:= true
Gui, Cancel
return
}

Here is a code:
Version 1 (with Gosub):
return
StartGui:
Gui, Add, Edit, x22 y19 w240 h120 vMyEdit, Here is default text
Gui, Add, Button, x22 y179 w100 h30 gGuiCloseOk, Ok
Gui, Add, Button, x162 y179 w100 h30 gGuiCloseCancel, Cancel
; Generated using SmartGUI Creator for SciTE
Gui, Show, w286 h231, My Gui Name
WinGetPos,,, Width, Height, My Gui Name
WinMove, My Gui Name,, (A_ScreenWidth/2)-(Width/2), (A_ScreenHeight/2)-(Height/2)
return
return
GuiCloseOK:
GuiControlGet, MyEdit
Gui, Destroy
return
GuiCloseCancel:
MyEdit:=""
Gui, Destroy
return
return
Esc::
Gui, Destroy
return
Place that code in your script anywhere you like. To call for the GUI add anywhere you want Gosub, StartGui. The content of Edit control you will get in MyEdit variable.
For example, if you want to call GUI by CTRL+ALT+z put that code in script anywhere you want:
return
!^z::
Gosub, StartGui
return
Version 2 (with function):
GuiFunc(DefaultText)
{
global MyEdit
MyEdit:=""
Gui, Add, Edit, x22 y19 w240 h120 vMyEdit, %DefaultText%
Gui, Add, Button, x22 y179 w100 h30 gGuiCloseOk, &Ok
Gui, Add, Button, x162 y179 w100 h30 gGuiCloseCancel, &Cancel
; Generated using SmartGUI Creator for SciTE
Gui, Show, w286 h231, My Gui Name
WinGetPos,,, Width, Height, My Gui Name
WinMove, My Gui Name,, (A_ScreenWidth/2)-(Width/2), (A_ScreenHeight/2)-(Height/2)
return
return
GuiCloseOK:
GuiControlGet, MyEdit
Gui, Destroy
return
GuiCloseCancel:
MyEdit:=""
Gui, Destroy
return
}
return
Esc::
Gui, Destroy
return
Place that code in your script anywhere you like. To call for the GUI, call GuiFunc(DefaultText) function with parameter that is text to display in Edit control by default. After running function global variable MyEdit is set to the content of Edit control. So you can use MyEdit variable anywhere outside the function. I know that you wanted function to return content of MyEdit variable but I tried it many ways with no success.
For example, put that code in your script anywhere you want. To call GUI press CTRL+ALT+z and to display content of MyEdit variable press CTRL+ALT+a :
return
!^z::
DefaultText:= "Here is default text"
GuiFunc(DefaultText)
return
return
!^a::
MsgBox, %MyEdit%
return
For both versions, if you decide to rename Window Title My Gui Name then keep in mind that you need to rename it in 3 places for script to work properly.
Also, always use AutoHotkey and its documenatation from http://ahkscript.org/ (current uptodate version, new official website)! AutoHotkey and its documentation from autohotkey.com is outdated and you may have some problems using them!

Based on alpha bravo's answer and Thierry Dalon's answer.
This is fixing the problem of either always having ErrorLevel=1 even when
the user clicks Ok button or not having ErrorLevel=1 when user clicks the cancel button or exits/interrupts the input box.
Also it uses WinWaitClose instead of while loop that seems better for me.
Removes unneeded lines having GuiControl and SendMessage.
MultiLineInputBox(Text:="", Defualt:="", Caption:="Multi Line Input Box"){
static
; futher helper variables
local is_interrupted := "" ; helper variable to know if submitted/interrupted [tn1]
Gui MultiLineInputBox:New,, % Caption
Gui, MultiLineInputBox: add, Text, r1 w600 , % Text
Gui, MultiLineInputBox: add, Edit, r10 w600 vMultiLineInputBoxContent, % DefaultText
Gui, MultiLineInputBox: add, Button, w60 gMultiLineInputBoxOK , &OK
Gui, MultiLineInputBox: add, Button, w60 x+10 gMultiLineInputBoxCancel, &Cancel
Gui, MultiLineInputBox: Show
Gui, MultiLineInputBox:+HwndMultiLineInputBox_hwnd
WinWaitClose, ahk_id %MultiLineInputBox_hwnd%
if (is_interrupted) {
ErrorLevel := 1
}
return MultiLineInputBoxContent
;----------------------
MultiLineInputBoxOK:
Gui, MultiLineInputBox:Submit
Gui, MultiLineInputBox:Destroy
return
;----------------------
MultiLineInputBoxCancel:
MultiLineInputBoxClose:
MultiLineInputBoxGuiEscape:
Gui, MultiLineInputBox: Cancel
Gui, MultiLineInputBox:Destroy
is_interrupted := True
return
}

Related

Cover inactive windows with GUI, Solutions to Variable Coordinates (AHK)

I collapse all my windows to title bars when not active. I want to cover these inactive windows with different color GUIs. The GUI will only need minimal functionality, just a way to color-code title bars when collapsed, and inactive. That way, I can tell what's what much easier when I look at a desktop full of title bars.
Although I know I have the correct coordinates stored as variables, the gui doesn't show up at all if I specify coordinates as numbers, or as variables. But if I don't specify any coordinates, the GUI appears in the middle of the screen.
This just seems like a combination of
-settimer, and a timer that updates the coordinates when the window moves.
-alwaysontop(ish) of a specific window for each gui(could use some help here, Looking to apply winset, top to a GUI when it's associated window is inactive, but also remain under any newly active window (to keep the GUI visible when looking at the desktop).
-using the corresponding window's y coordinate to know how high to place the GUI(main issue, although I know I have the correct coordinates stored as variables)
-displaying a different color for each GUI.
-The GUI should span across the entire screen width, and be 1/17 the screen height (about the height of the title bar with my screen/resolution).
-winhide a window's gui when it's associated window is active, and winshow when inactive
#SingleInstance,Force
WinGetPos , X_SciTEWindow, Y_SciTEWindow, Width_SciTEWindow, Height_SciTEWindow, ahk_class SciTEWindow ;I don't even need the X_SciTEWindow, because the bars will all be aligned at x0, but it's there...
SysGet, aScreenHeight, 1
bar_height := Round(aScreenHeight / 17)
Gui, Color, aqua,FFB1B1
Gui, Show, w%A_ScreenWidth% h%bar_height%, SomeStupidBar
WinSet, Style, -20xC40000
Winmove, %SomeStupidBar%, x0, y%Y_SciTEWindow%, w%A_ScreenWidth%, h%bar_height%
MsgBox, Time to move the window to x0, y%Y_SciTEWindow%, w%A_ScreenWidth%, h%bar_height%
Winmove, %SomeStupidBar%, x0, y%Y_SciTEWindow%, w%A_ScreenWidth%, h%bar_height%
return
Esc::ExitApp
SetTimer, ShowGui, 500
ShowGui:
IfWinNotExist, ahk_class AutohotkeyGUI
{
Gui, +Owner%WinID% +Border +ToolWindow
Gui, Show, NoActivate x%X% y%Y% w51 h431, %GuiTitle%
}
else
{
WinWaitActive, ahk_class SciTEWindow
WinGetPos, X_SciTEWindow, Y_SciTEWindow,,, ahk_class Notepad
WinGet, WinID, ID, ahk_class SciTEWindow,,,
IfWinNotExist, ahk_class AutohotkeyGUI
WinGetPos, %SomeStupidBar%, , , , ahk_class AutohotkeyGUI
If %SomeStupidBar%<>X - 56
WinMove, ahk_class AutohotkeyGUI, X - 56
}
return
Any help would be greatly appreciated.
#NoEnv
#SingleInstance Force
Gui, SciTE: +Owner -Caption
Gui, SciTE: Color, aqua
Gui, Notepad: +Owner -Caption
Gui, Notepad: Color, red
SysGet, aScreenHeight, 1
bar_height := Round(aScreenHeight / 17)
SetTimer, ShowGui, 500
return
Esc::ExitApp
ShowGui:
If !WinExist("ahk_class SciTEWindow") ; means "NOT"
Gui, SciTE: Cancel
else
{
WinGetPos, X_SciTE, Y_SciTE,,, ahk_class SciTEWindow
If X_SciTE >= 0
Gui, SciTE: Show, NoActivate x%X_SciTE% y%Y_SciTE% w51 h%bar_height%, SciTEWindow
}
If !WinExist("ahk_class Notepad")
Gui, Notepad: Cancel
else
{
WinGetPos, X_Notepad, Y_Notepad,,, ahk_class Notepad
If X_Notepad >= 0
Gui, Notepad: Show, NoActivate x%X_Notepad% y%Y_Notepad% w51 h%bar_height%, Notepad
}
return
#If WinActive("ahk_class AutoHotkeyGUI")
~*LButton Up::
WinGetTitle, ActiveTitle, A
WinActivate, ahk_class %ActiveTitle%
return
#If

How can I insert text from a textbox to a file in autohotkey?

I am trying to make a text editor from autohotkey.
Though, I am having trouble getting a button to insert text from a textbox into a file.
Here is my code
Gui, Add, Picture, x2 y-1 w1360 h40 , chars\greenbox.png
Gui, Add, Tab, x2 y39 w1360 h660 , Untilted Project
Gui, Font, S8 CBlue Bold, Verdana
Gui, Add, Button, x2 y-1 w90 h20 vSave_text, Save
Gui, Add, Edit, x2 y59 w1350 h-90 vUsertextinput, Edit
Gui, Add, Edit, x2 y59 w1290 h580 , ';Created Using ADI
Gui, Font, S8 CGreen Bold, Verdana
Gui, Show, x200 y139 h666 w1370, ADI Editor
Return
GuiClose:
ExitApp
Save_text:
FileAppend,
(
%Usertextinput%
), Projects\Untitled1.ahk
Your save button needs a g-label, not a variable, thus gSave_text.
To access the contents of the edit field you have to run GuiControlGet on it.
Here is a working example:
Gui, Add, Button, gSave_text, Save
Gui, Add, Edit, vUsertextinput, Test123
Gui, Show
Save_text() {
GuiControlGet, Usertextinput
FileAppend, %Usertextinput%, Projects\Untitled1.ahk
}

Disable/Enable GUI Elements in AHK

Gui, Add, Radio, vVar, Sample Text!
Gui, Add, Button, gToggle vEnable, Toggle
Gui, Show
Return
Toggle:
GuiControl, Disable, Var
Return
This code creates a Radio and the "Toggle" function disables it. I keep seeing this technique being used to disable/grey-out elements, but I want something that toggles it on and off, but I'm not sure how to create it.
Thought about it for a bit, came up with this:
isEnabled := True
Gui, Add, Radio, vVar, Sample Text!
Gui, Add, Button, gToggle vEnable, Toggle
Gui, Show
Return
Toggle:
isEnabled := !isEnabled
if isEnabled
GuiControl, Enable, Var
if !isEnabled
GuiControl, Disable, Var
Return
Is there any better way to do it?
Gui, Add, Radio, vVar, Sample Text!
Gui, Add, Button, gToggle vEnable, Toggle
Gui, Show
Return
Toggle:
GuiControlGet, enabledState, Enabled, Var
enabledState := !enabledState
GuiControl, Enable%enabledState%, Var
Return
With this version you don't need to track the enabled state.

Autohotkey script to download to a specific folder on the computer

I need Firefox to always open Desktop in the Save as dialogue on saving files, so I can type in the name of the folder on the Desktop and save the file where I want. That would be a simple and very efficient way of grouping downloaded files. The problem is that Firefox opens the last save folder in the Save as dialogue window, and I can't do this in a reasonable number of steps. To get Desktop automatically opened in the Save as dialogue the best I could think of is this autohotkey script, and I have a problem with it:
!+^s::
MouseMove, %A_CaretX%, %A_CaretY%
CoordMode, Mouse, Screen
MouseGetPos, xpos, ypos
SetMouseDelay, 2
MouseMove,445,46
Click Left
Send,Desktop
Send,{Enter}
MouseMove, %xpos%, %ypos%
Click Left
CoordMode, Mouse, Screen
MouseGetPos, xpos, ypos
SetMouseDelay, 2
MouseMove,445,46
Click Left
MouseMove,%xpos%, %ypos%
Click Left
Input, L, V L1
Loop {
Input, L, V L1 T1.4
If (ErrorLevel = "Timeout")
Break
}
Send,^{Down}
Send,{Enter}
MouseClick,Left,720,473
MouseClick,Left,720,473
return
The problem with this script is the Input command - it doesn't wait for me to type in the name of the folder but executes the following command immediatelly.
EDITED: The script is now fully working (thanks to Forivin). An additional line with Input comamand "Input, L, V L1" was required for the script to pause and wait for the name of the folder to be typed in. I've used MouseClick command and coordinates that work for my monitor to confirm the dialogue box. Confirming the dialog box with Enter (4 times) doesn't work accurately on my computer for some reason. EDIT2: Added two lines, in order to make use of the drop down list folder name suggestions, so the whole folder name doesn't need to be typed in.
Using the Control*-commands would be a much more reliable way of doing this:
!+^s::
WinGet, hWnd, ID, A ;Get handle of active window
;Navigate the the users desktop folder
ControlFocus, ToolbarWindow324, ahk_id %hWnd%
ControlClick, ToolbarWindow324, ahk_id %hWnd%,,,2, NA
ControlSetText, Edit2, `%HOMEPATH`%\Desktop\, ahk_id %hWnd%
ControlSend, Edit2, {Enter}, ahk_id %hWnd%
;Set focus to the folder list
Sleep, 100
ControlFocus, DirectUIHWND2, ahk_id %hWnd%
Input, L, V L1 T2 ;wait until you start typing a folder name (if you just wait 2 seconds, the download will be canceled)
If (ErrorLevel = "Timeout") { ;if you waited too long:
ControlClick, Button2, ahk_id %hWnd%,,,, NA ;click the Cancel button
Return ;end of the hotkey
}
Loop { ;wait until you haven't typed a new letter for 0.4 seconds
Input, L, V L1 T0.4
If (ErrorLevel = "Timeout")
Break
}
ControlGetText, button1Text, Button1, ahk_id %hWnd%
If (button1Text = "&Open") { ;If your windows isn't English, you need to replace the word "Open", if you're confused remove the if statement (but leave the content)
ControlClick, Button1, ahk_id %hWnd%,,,, NA ;click the Open button
Sleep, 100
}
ControlClick, Button1, ahk_id %hWnd%,,,, NA ;click the Save button
Return

AHK combine working 'Drop Down + List Box' w/ 'ListBox w/ double click selection'

First time post & very thankful for all the useful posts on this site.
The following are two examples of working code that I have tweaked from this site and ahk's board. Credit goes out to ahk's "garry" for the combined boxes and to this site's "Robert Ilbrink" for the idea and functionality on the double click return current selection.
In short I have two pieces of working code that I would like to combine in the following way:
I am looking for a way to add the functionality of the double click in the second code example to the combined 'drop down + listbox' example shown below.
*Note: If I could keep the same button functionality that would be great because not only can you double click, but you can also hit enter with the highlighted text and it will retrieve and send the selected text.
First Program(Drop Down + ListBox)
gosub,ddlx
ACTIONMOVIS=MISSION|007
COMEDIMOVIS=QENGUIN|BRUSALL
HORRORMOVIS=RING|13GHOST
FANTASYMOVIE=AVATA|CHOCOLAT
Gui, Add, DropDownList,gAPLY x12 y70 w100 h100 vDROPDOWN, %LST%
Gui, Add, ListBox, x132 y70 w80 h180 vLISTBOXM
gui,Show
GuiControl,1: Choose,dropdown,Comedy ;-- << preselect
gosub,aply
return
;-- this can be interessant instead using a very long line --
DDLX:
LST=
(Ltrim Join|
Action
Horror
Comedy
Fantasy
Drama
)
return
APLY:
gui,1:submit,nohide
guicontrol,1:,LISTBOXM,|
listboxm=
If DROPDOWN=Action
LISTBOXM=%ACTIONMOVIS%
If DROPDOWN=Comedy
LISTBOXM=%COMEDIMOVIS%
If DROPDOWN=Horror
LISTBOXM=%HORRORMOVIS%
If DROPDOWN=Fantasy
LISTBOXM=%FANTASYMOVIE%
guicontrol,1:,LISTBOXM,%LISTBOXM%
listboxm=
return
GuiClose:
ExitApp
second program (ListBox with Double Click & Enter Functionality)
#SingleInstance Force
Gui, Add, ListBox, h150 w140 vMyListBox gMyListBox, MISSION|007|RING|13GHOST|QENGUIN|BRUSALL| AVATA|CHOCOLAT
Gui, Add, Button, Default, Input
Gui, +AlwaysOnTop
Gui, Show
return
MyListBox:
if A_GuiControlEvent <> DoubleClick
return
GuiControlGet, MyListBox ; Retrieve the ListBox's current selection.
Send, !{Esc}
Sleep, 200
SendInput, %MyListBox% `
return
ButtonInput:
Gui, Submit, NoHide
Send, !{Esc}
Sleep, 200
SendInput, %MyListBox% `
Return
GuiClose:
GuiEscape:
Gui, Destroy
ExitApp
Thanks again in advance for your ideas and suggestions.
-Alex

Resources