Is there a simple way to write, in any programming language, a command that reads, in the terminal, an input line, allowing the user only to delete the last char he typed, and that will work without any problem of any kind, in all Linux “flavors”?
For example, if someone had to write this function in C, how did he achieve that?
This command/function has to work on any Linux flavour, on any kind of terminal emulator, in any country of the world…
Is that possible?
Actually I’m trying to do this but in Go. But I don’t think there’s a difference if I do this in Go or in C or in any other language, since, I guess, the problem is on the terminal, stty, config side…
I’m writing a TUI where - of course - I need to read the user’s input. I read it only one “key” at the time. With “key”, I mean: a single keyboard’s key or a combination of them: a letter, a digit, a function key, a keypad’s key; the Enter, Esc, or Tab key; the Ctrl+something combination of keys, and so on. (I don’t even know the right term I should use to define that “input key”.)
I understand the “escape sequences” quite well. I can easily read all keyboard and mouse inputs. All of them start with the “escape” ASCII character. I know how to parse those sequences and I can manage all kinds of user’s input; I can even follow the mouse cursor while it’s moving on the screen. I know the position of the cursor, the row and the column number, I know on which cell the user clicked and which mouse button he clicked. I can even know when and where he’s using the mouse wheel…
What I don’t understand is the “stty” thing and all the issues that arise from using different kinds of terminal’s emulators. I guess all problems come from that.
Since I have no experience in this kind of matters, I’ve googled around, and I’ve found solutions that work for me. But it’s very likely that, for another person, in another part of the world, and which uses another Linux’s flavor and another kind of terminal emulator, this solutions won’t work. I use the gnome terminal on Ubuntu 24.
In my program, the user usually has to input one “key” at the time, and I use that single key to do something. But other times the user has to input a whole line.
I wrote a function like this one below, to read a whole line from the user. Of course I have to read that line one “key” at the time:
var char rune
var line, s string
for {
fmt.Scanf("%c", &char)
s = string(char)
switch s {
case BACKSPACE:
// delete the last "input key" from line
// ...
case ESC:
// dump this new "input "key": it's an escape sequence
// ...
case ENTER:
// return the line
return line
default:
// add the new "char"
line += s
}
}
→ Add, to the line, any key the user is typing, discarding the escape sequences (arrows, keypads, mouse buttons, and so on). When he types the backspace, delete the last key you had read. When he types Enter, you are finished.
Maybe this function is not very well written, but, in my computer, it works fine… only if I put this line before:
exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run()
which is the same, I guess, as if I were writing this in bash:
stty -F /dev/tty cbreak min 1
I tried studying what that exactly means, but I’m still away from a deep understanding… Unfortunately, I don’t feel familiar with these “tty”, “stty”, “config” things. I guess they are simple, but I just don’t get it at the moment.
Anyway, with that “stty” command, I can read one “input key” at the time, and that’s it.
Now, other people tried this command of mine and it didn’t work. There were issues when reading from the command line.
The question is:
→ How can I achieve a simple thing like this: reading an input line from the user, being certain that it will work on any Linux distro and on any terminal emulator?