2

I'm trying to implement an application similar to a chat client where messages can arrive while the user is typing his own message.

I'll explain how I want my program to behave with an example: Before an incoming message:

>user partial input

After an incoming message:

>the new message
>user partial input(cursor is here)

Instead what naturally happens after an incoming message is this:

>user partial input the new message
>(cursor is here)

After that the user can still use backspace to delete what he wrote before but it doesn't show on the screen and there's a UI mess overall.

Is there any way to achieve the desired behavior without using ncurses?

Thank you.

Edit: Sorry, I forgot to write what my environment is, it's Cygwin. Thanks for all of the answers.

6
  • 3
    Why don't you want to use ncurses? Commented May 27, 2011 at 16:59
  • 1
    Well, you certainly can't do it with standard C++ library stream I/O functions. Commented May 27, 2011 at 16:59
  • No particular reason not to use ncurses, just wondering if there is another way. Commented May 27, 2011 at 17:03
  • 2
    You can undoubtedly accomplish it without ncurses, but it may be pretty ugly. On Windows, you'd use the console API directly. On Linux, you'd (probably) want (or, more accurately, have) to use ANSI escape codes directly. They're a bit ugly and unwieldy, but 20 years ago (or more) lots of us wrote code that way fairly routinely, and I'm pretty sure there's nothing to prevent doing it today. At the same time, I feel obliged to point out that ncurses is a lot better alternative. Commented May 27, 2011 at 17:05
  • 2
    This would definitely be more suited to some sort of GUI application rather than the terminal. Commented May 27, 2011 at 17:10

4 Answers 4

4

While ncurses may be the most flexible and simple way to achieve this, you can do it yourself with some work.

You have to arbitrate the IO yourself. You can use "\r" to return to the beginning of a line without ncurses or any platform-specific terminal interaction.

The overall flow would be:

  • You have an input loop that reads into an input buffer character-wise. The default behavior is to echo every character. Once you receive a newline, you would commit that line from your buffer and print with a newline.
  • If you get notified of an incoming message, you should print a "\r" to move the cursor back to the beginning of the line, print spaces to clear the line followed by another "\r" to restore the cursor to the beginning, print the message with a newline, then print the current buffered input.

There are lots of edge cases to consider here, but ncurses is not your only option. This technique works on both Windows and Linux as far as I have tested.

Sign up to request clarification or add additional context in comments.

1 Comment

heavily underrated answer. Simple and clean.
1

There is no (practical) solution without using a GUI or ncurses.

I wrote something similar with ncurses a number of years back. It was minimal (two simple windows) but less than 100 lines of code had anything to do with ncurses so it is hardly an insurmountable obstacle.

The problem with ncurses is that it looks (and is) somewhat quirky at first. The documentation isn't as helpful as it could be and not that many people know or care that much about it anymore so when you paint yourself into a corner it is hard to find help. But if you keep it simple you should be fine.

Comments

0

You could send the escaped control sequences to the terminal yourself, but it's just the same as re-implementing ncurses :)

Comments

0

Yes, as the comments say, you'd have to interact with the terminal itself, either through ncurses, ANSI codes, or the (horrible) windows API. There's no way to use the standard streams to achieve that (being streams they only do input/output, and are not display or cursor aware).

Also, streams expose a synchronous (blocking) API, so you can't read from one and write to another without resorting to threads or a reactor.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.