Text Input

I know this has been discussed before, but I’m looking for something slightly different… a DOS type environment. Exactly what you get in Command Prompt in Windows, with the user input and computer output on separate lines scrolling up the screen when you hit return.

I found some code by @dave1707 and stripped out the input rectangle part, but I’m struggling to get past this problem… I don’t want to ‘hide keyboard’ when hitting return and yet if I just comment out that one line, the text returned to ‘str’ accumulates to all that was previously typed. Maybe hideKeyboard does other things as well but I can’t find any other info on it. Thanks :wink:

function setup()
x=0
l=0
showKeyboard()
end

function draw()
    background(30,30,0,255)
    textMode(STANDARD)
    text(">",40,380)  
  
    buffer = keyboardBuffer()
    
    fill(255)
    textWrapWidth(650)
    text(buffer,60,380)  
    
      if x==1 then 
        text("... is not recognised as an internal or external command...",60,380+l)
      end
     
end

function touched()    
    showKeyboard()
end

function keyboard(key)
    if key == RETURN then
       str = buffer
       hideKeyboard()  -- why can't I comment out this line without affecting other things??
       print(str, x, l)
       x=1
       l = l+20
    end    
end

@David The keyboardBuffer doesn’t get cleared unless you do a hideKeyboard/showKeyboard. The keyboard code can be changed to not use the keyboardBuffer, but you’ll have to code for the backspace key etc.

Thanks @dave1707… that explains it. I’d rather not have the keyboard continually showing/hiding so what is the alternative syntax to get text into a string? Presumably I couldn’t just ‘extract’ the end of the keyboard buffer between CR?
Or would it eventually overflow?

You can use the keyboard function to assemble the text character by character.

@David Is this something like what you’re after.


function setup()
    strTab={}
    buffer=""
    showKeyboard()
    textMode(CORNER)
end

function draw()
    background(30,30,0,255)
    fill(255)
    if buffer~="" then
        text(buffer,10,400)
    end
    for z=1,#strTab do
        text(strTab[z],10,420+(#strTab-z)*20)
    end
end

function touched()    
    showKeyboard()
end

function keyboard(key)
    if key == RETURN then
        table.insert(strTab,buffer)
        buffer=""
    elseif key==BACKSPACE then
        buffer=string.sub(buffer,1,string.len(buffer)-1)
    else
        buffer=buffer..key
    end   
end

Wow, thanks @dave1707 ! I inserted a counter to keep track of the last user input and print it to console to check, and that is exactly what I’m after.

function setup()
    strTab={}
    buffer=""
    showKeyboard()
    textMode(CORNER)
    x=0
end

function draw()
    background(30,30,0,255)
    fill(255)
    if buffer~="" then
        text(buffer,10,400)
    end
    for z=1,#strTab do
        text(strTab[z],10,420+(#strTab-z)*20)
    end
end

function touched()    
    showKeyboard()
end

function keyboard(key)
    if key == RETURN then
        table.insert(strTab,buffer)
        buffer=""
        x=x+1
        print(strTab[x])
    elseif key==BACKSPACE then
        buffer=string.sub(buffer,1,string.len(buffer)-1)
    else
        buffer=buffer..key
    end 
    
end

It all makes sense too, except I don’t 100% get how this part works to scroll the text up.

    for z=1,#strTab do
        text(strTab[z],10,420+(#strTab-z)*20)
    end

@David Each input is going into a table entry (strTab). The “for” loop is getting each entry and displaying to the screen (text). The text is starting at a y value of 420. Since I want the text to appear from top to bottom, the first entry is the highest up the screen. So that’s why I do 420+(#strTab-z)*20. If there are 5 entries, then the first entry is at 420+(#strTab(5)-z(1))*20 which is at 500. The second entry will be at 420+(5-2)*20 which is 480, and so on.

Ahhhh, light bulb turned on… I get it now. Many thanks @dave1707!
And thanks @Andrew_Stacey too :wink:

@dave1707 Further advice needed. I’m intending to write a fairly simple text adventure game, and just trying to get the basic input/output structure formatted.
This is where I’m up to, and it’s mostly as I want, but a few issues…

1 The text doesn’t wrap around.

2 Only want the > for user input, not computer responses.

3 Slightly different colour for computer responses would be nice.

4 Maybe a double line spacing between each pair of input/outputs.

function setup()
    strTab={}
    buffer=""
    showKeyboard()
    textMode(CORNER)
    str=0
end

function draw()
    background(30,30,0,255)
    fill(255)
    text(">",10,380)
    if buffer~="" then
        text(buffer,30,380)
    end
    for z=1,#strTab do
        text(">",10,400+25*z)
        text(strTab[z],30,420+(#strTab-z)*25)
    end
end

function touched()    
    showKeyboard()
end

function keyboard(key)
    if key == RETURN then
        table.insert(strTab,buffer)
        buffer=""
        table.insert(strTab,"This is an automatically generated response.... but unfortunately it goes off the edge of the screen, so will need <CR> to wrap the text")
        str=str+1
        print(strTab[2*str-1])
            
    elseif key==BACKSPACE then        
        buffer=string.sub(buffer,1,string.len(buffer)-1)    
    else
        buffer=buffer..key
    end 
    
end

Thanks :wink:

@David I don’t have time to fix this the right way, but try what I have so far. I know I have to not print the #, that’s what I’m using to identify a computer response.


function setup()
    textWrapWidth(WIDTH-50)
    strTab={}
    buffer=""
    showKeyboard()
    textMode(CORNER)
    str=0
end

function draw()
    background(30,30,0,255)
    fill(255)
    text(">",16,380)
    if buffer~="" then
        text(buffer,30,380)
    end
    for z=1,#strTab do
        if string.sub(strTab[z],1,1)=="#" then
           fill(255,0,0) 
           text(strTab[z],30,420+(#strTab-z)*50)
        else
            fill(255)
            text("> "..strTab[z],30,420+(#strTab-z)*50)
        end
    end
end

function touched()    
    showKeyboard()
end

function keyboard(key)
    if key == RETURN then
        table.insert(strTab,buffer)
        buffer=""
        table.insert(strTab,"#This is an automatically generated response.... but unfortunately it goes off the edge of the screen, so will need <CR> to wrap the text")
        table.insert(strTab,"#")
        str=str+1
        print(strTab[2*str-1])

    elseif key==BACKSPACE then        
        buffer=string.sub(buffer,1,string.len(buffer)-1)    
    else
        buffer=buffer..key
    end 
end

You can use @dave1707’s solution, but you also might do this:

when the user inputs something, automaticly place the ‘>’ in front of that text so that the user can’t ‘cheat’ by placing a ‘#’ as the first char

to get rid of the ‘#’ just start displaying it from the second char, so that would be



function setup()
    textWrapWidth(WIDTH-50)
    strTab={}
    buffer=""
    showKeyboard()
    textMode(CORNER)
    str=0
end

function draw()
    background(30,30,0,255)
    fill(255)
    text(">",16,380)
    if buffer~="" then
        text(buffer,30,380)
    end
    for z=1,#strTab do
        if string.sub(strTab[z],1,1)=="#" then
           fill(255,0,0) 
           text(string.sub(strTab[z], 2) ,30,420+(#strTab-z)*50)
        else
            fill(255)
            text(strTab[z],30,420+(#strTab-z)*50)
        end
    end
end

function touched()    
    showKeyboard()
end

function keyboard(key)
    if key == RETURN then
        table.insert(strTab, '> ' .. buffer)
        buffer=""
        table.insert(strTab,"#This is an automatically generated response.... but unfortunately it goes off the edge of the screen, so will need <CR> to wrap the text")
        table.insert(strTab,"#")
        str=str+1
        print(strTab[2*str-1])

    elseif key==BACKSPACE then        
        buffer=string.sub(buffer,1,string.len(buffer)-1)    
    else
        buffer=buffer..key
    end 
end

Gosh, thanks guys! That’s amazing… I’m just working through it to make sure I fully understand it all. I see that user input is now every 3rd entry in the table with the inclusion of # so changed the print to reflect this…

print(strTab[3*str-2])

I changed response colour to yellow and made it FULLSCREEN as default. Didn’t realise that the text would automatically adjust to fill screen - cool!

I just want to move the initial cursor up a little, away from the icons, and reduce spacing between input/output pairs to 1 or 2 lines. Looking good! :wink:

I thought I’d managed to get this right, but unfortunately it all changes if the number of lines in the response is different - it will vary.
If you edit down or increase the lines you can see the spacing goes adrift. It looks great though!

function setup()
    displayMode(FULLSCREEN)
    font("Courier")
    textWrapWidth(WIDTH-50)
    strTab={}
    buffer=""
    showKeyboard()
    textMode(CORNER)
    str=0
end

function draw()
    background(30,30,0,255)
    fill(255)
    text(">",30,400)
    if buffer~="" then
        text(buffer,45,400)
    end
    for z=1,#strTab do
        if string.sub(strTab[z],1,1)=="#" then
           fill(255,255,0) 
           text(string.sub(strTab[z], 2) ,30,420+(#strTab-z)*40)
        else
            fill(255)
            text(strTab[z],30,465+(#strTab-z)*40)
        end
    end
end

function touched()    
    showKeyboard()
end

function keyboard(key)
    if key == RETURN then
        table.insert(strTab, '> ' .. buffer)
        buffer=""
        table.insert(strTab,"#FORREST\
You are deep inside a dark forrest. The undergrowth makes it very difficult to wander off a path that leads to the South.\
There appears to be something hidden in the bushes to your left.")
        table.insert(strTab,"#")
        str=str+1
        print(strTab[3*str-2])

    elseif key==BACKSPACE then        
        buffer=string.sub(buffer,1,string.len(buffer)-1)    
    else
        buffer=buffer..key
    end 
end

@David You can use the code below for the computer response. You can use the value of “h” to determine the amount of spacing you need.

w,h=textSize(strTab[z]) 

@David Try this for draw(). You might have to adjust this for your liking. I use textSize() and a variable lineSize.


function draw()
    background(30,30,0,255)
    fill(255)
    text(">",30,400)
    if buffer~="" then
        text(buffer,45,400)
    end
    lineSize=0
    for z=#strTab,1,-1 do
        if string.sub(strTab[z],1,1)=="#" then
           fill(255,255,0) 
           text(string.sub(strTab[z], 2) ,30,465+lineSize)
        else
            fill(255)
            text(strTab[z],30,465+lineSize)
        end
        w,h=textSize(strTab[z])
        lineSize=lineSize+h
    end
end

@dave1707 that is absolutely fantastic! Thank you so much :wink:
That part is completely sorted now, so onto the map and input parser next.
I wrote a couple of text based adventures in Atari Basic and 6502 machine code, over 30 years ago, and often thought I’d like to re-learn those skills. Codea is immense fun and with such helpful support here I’m making great progress.

@David I enjoyed writing in 6502 assembler on my Apple II. 6502 assembler was about 1000 times faster than basic.

It looks like posts aren’t in the correct order. I wasn’t able to get into the forum for awhile. I kept getting “server not responding”. My 7:05 and 7:42 posts should be after the 4:43 post and before my 5:03 and 5:11 posts and before David’s 4:48 post.

Hi @dave1707 Yes, I couldn’t connect earlier as well.
I also found that Basic was too slow so I learnt assembler and machine code. I still have the books and look through them from time to time wondering how the hell I ever managed to understand it!

– answered my own question –