5

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.

Ram Rachum
  • 84,019
  • 84
  • 236
  • 374
  • 1
    You seem to know what you *want*. Where do you have difficulties implementing it? – MCL Sep 08 '14 at 13:40
  • I don't know how to deal with the `gui` command. – Ram Rachum Sep 09 '14 at 10:25
  • The [Gui docs](http://ahkscript.org/docs/commands/Gui.htm) have a very comprehensive explanation of possible parameters and many examples. This should get you started. – MCL Sep 09 '14 at 12:36
  • For the textbox, you are looking for `Gui, Add, Edit, R20 vMyEdit ` - check out the full example in the AHK help file that came with your installation – 576i Sep 09 '14 at 12:59

5 Answers5

5

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 }
Community
  • 1
  • 1
alpha bravo
  • 7,838
  • 1
  • 19
  • 23
  • 1
    **Potential bug**: Once a MultiLineInputBox has been created, the prompt text for all subsequent input boxes cannot be changed. ([screenshot](https://i.stack.imgur.com/s5Tvf.png)) – Stevoisiak Aug 31 '17 at 17:36
  • @ThierryDalon The behavior may have changed in newer versions of AutoHotkey. Unfortunately, I don't remember which version I was using when I saw the bug. – Stevoisiak Jun 20 '18 at 18:47
  • @StevenVascellaro: now I have this bug too! – Thierry Dalon Jul 11 '18 at 19:53
  • @StevenVascellaro: I think I've come to a fix of this bug. See my separate answer https://stackoverflow.com/a/51300246/2043349 – Thierry Dalon Jul 12 '18 at 08:00
1

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:
enter image description here

And here is what it returns printed in a MsgBox: Click

Forivin
  • 14,780
  • 27
  • 106
  • 199
  • I recommend renaming the parameter `Text` to `Title`. It matches the parameter name used by InputBox and describes the intended use a bit better – Stevoisiak Aug 31 '17 at 17:40
1

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
}
Andrew D. Bond
  • 902
  • 1
  • 11
  • 11
Thierry Dalon
  • 779
  • 5
  • 21
0

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!

vasili111
  • 6,032
  • 10
  • 50
  • 80
  • A few issues: 1. Do you mind providing it in a function rather than a subroutine? I'm more comfortable with that. I'd expect it to be a function that takes the prompt text and the placeholder text to put in the text input, and return the text the user put if he pressed okay or some null value if he pressed cancel or esc. 2. Accelerators are letters in the button text that are underlined, so if you press alt and that letter the button is invoked. 3. Do you mind indenting the code? It would be easier to read and understand. – Ram Rachum Sep 10 '14 at 17:08
  • @RamRachum Version 2 added. As far as I understand there is what you need except that function does not returns anything. After running function global variable `MyEdit` is set to the content of *Edit* control. Please check it. – vasili111 Sep 10 '14 at 19:16
  • @RamRachum I have improved version 2. Now you can call function without `global MyEdit` and `MyEdit:=""` before calling function. They are moved inside function. – vasili111 Sep 11 '14 at 05:14
  • So many explanations... Instead of simply a function that returns a value, like we've been using for decades in the software development world. Why? – Ram Rachum Sep 11 '14 at 15:21
  • @RamRachum From your profile I see that you are professional programmer but not everyone else are. Not everything that is easy for you is also easy for others. For example, programming for me is only hobby and I don't have special education in programming and when I ask questions about programming I personally prefer when everything is explained, its easy for me to understand that way. Also many other people who are using AutoHotkey are not professional programmers and some of them will read that answer and maybe they will find something useful for them. – vasili111 Sep 11 '14 at 17:51
  • There's lots of things in software development and in life that I'm a novice in. Being inexperienced is no shame. But I'd prefer to get *answers* only from experienced people. In the same way I wouldn't try to answer in a field where I'm a novice in, I'd let other people answer and maybe learn from them. – Ram Rachum Sep 12 '14 at 17:51
  • @RamRachum You have a very strange reaction when someone is trying to help you. Stackoverflow and other stackexchange websites are not only for experts. There are many people that are not experts and are actually helping each other and there is no rule that states that only experts should answer. If you need only expert answer next time you can write in your question: **Please answer if you are only expert. All others are not welcomed!**. But in that case I don't think anyone will help you. – vasili111 Sep 12 '14 at 18:08
0

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
}
Omar
  • 6,681
  • 5
  • 21
  • 36