I think this problem roots from input and output is at the same window. Is there any way to make it cleaner such that the new message will be separated from user's current input?
Instead of reading lines from the terminal in cooked mode with plain fgets() and relying on the terminal's almost-nonexistent editing support, I would suggest switching to a full line-editing library such as editline, tecla, or readline – the latter is what Bash uses.
In-process line editing means that the program receives input character-by-character, and already knows what's entered before the user presses Enter. As well as giving you all of the usual text-editing keyboard shortcuts, using in-process line editing lets you clear the whole thing from display, then output a received message, then re-display the prompt with the text pre-filled (and still editable!).
Not all libraries make this convenient; e.g. with readline, the clearing may need to be done manually, although it does provide a redisplay() function that you'd call after output. Unfortunately I don't have any particular suggestions as to what specific library would work better. I see that the Linenoise library has specific support for this use case, but that's just what I found on Google right now.