How to set console cursor position for stdout - c++

I want to set cursor position to print a char on console screen. Is there a solution without using ncurses library.
Is there an equivalent call for SetConsoleCursorPosition in Linux from example below:
void print (int x, int y, char c) {
COORD p = { x, y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), p);
printf("%c", c);
}

Perhaps a little history is in order. What you call the “console” in Windows is really an example of a terminal emulator; however, unlike traditional terminal emulators, Windows provides direct access to the terminal via its Console API. The traditional approach taken by terminals (and hence terminal emulators) was to interpret escape sequences, each of which instructs the terminal to perform some operation.
Unfortunately, as you might imagine, terminals' capabilities varied widely (some could even draw graphics of one sort or another), and so not all terminals use the same set of escape sequences. These days you'd be very unlucky to encounter something that didn't implement a superset of the ANSI/VT100 escapes; if you're happy to only support ANSI/VT100 and derivatives, you could send ESC [ n ; m H, where n is the row number and m the column number.
However, if you do do that, your code won't work if it's presented with anything exotic. In that case, you really should consider using a curses library (ncurses being a common but not the only example), even if you're only using it to extract information from the terminfo database (though I'd strongly recommend just using the curses library).
Finally, a note: the code you quote from Windows won't necessarily work(!) Why? Because printf() does buffered output, and there's no guarantee that your character will be sent to the console before you change the cursor position again. You could fix this by using fflush(stdout), but honestly if you're using SetConsoleCursorPosition you may as well just use WriteConsole and be done with it.
Additional useful information
You can actually get a version of curses that runs on Windows; see e.g. PDCurses. If you were to use curses, then, you wouldn't need any Windows-specific code either, and you'd work on whatever terminal was in use.

Related

making sure program is in a terminal

I was trying to add colors to some strings that have to be displayed in a terminal using ansi escape code. So far I haven't grasped the whole ascii escapes code thing, just trying out by copy pasting some escape codes. Then saw this answer which asked to verify that program should check that its being executed in a terminal or else continue without polluting strings with escape codes?
Answer explains to use a *nix based function isatty() which I found out resides in unistd.h which in turn wasn't promoted to cunistd by cpp standard based on my understanding that it wasn't in c's standard at first place.I tried to search SO again but wasn't able to understand well. Now I have two questions regarding this :
In what environment(right word?) can a program - using ascii escape codes, be executed that it requires an initial check? since I'm bulding for cli only.
What would be a proper solution according to ISO cpp standards for handling this issue? using unistd.h? would this use confine to modern cpp practices?
Also is there anything I should read/understand before dealing with ansi/colors related thing?
On a POSIX system (like Linux or OSX) the isatty function is indeed the correct function to determine if you're outputting to a terminal or not.
Use it as this
if (isatty(STDOUT_FILENO))
{
// Output using VT100 control codes
}
else
{
// Output is not a TTY, could be a pipe or redirected to a file
// Use normal output without control codes
}

How to manipulate the terminal output buffer directly

I want to write a game in Linux terminal(In C/C++), so firstly I should be able to print the character I want to it. I tried with "printf()", but it seems a little inconvenient. I think there should be a character buffer for the output characters for a terminal. Is there any way to directly manipulate the buffer?
Thanks a lot.
It goes in a way different manner.
A terminal is nothing else, but a character device, which means it is practically unbuffered. Despite of this, you still can manipulate the screen position with appropriate sequences of characters, called "escape sequences". For example, if you issue the \e[A (0x1B 0x91 0x41) sequence, the cursor goes one line up while leaving the characters intact, while if you issue \e[10;10H, (0x1B 0x91 0x31 0x30 0x3B 0x31 0x30 0x48), your cursor will go to column 10 of row 10 (exactly what you want). After you moved the cursor, the next character you write out goes to that position. For further information on escape sequences, look at this link.
Another important thing to know about is the dimensions of your terminal. ioctl can inform you about the size of the terminal window:
#include <stdio.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
int main ()
{
struct winsize ws;
ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws);
printf ("Rows: %d, Cols: %d\n", ws.ws_row, ws.ws_col);
return 0;
}
Note that the technique mentioned above is a solution to send commands to the terminal emulator connected to your pseudo terminal device. That is, the terminal device itself remains unbuffered, the commands are interpreted by the terminal emulator.
You might want to use the setbuf function, which allows you tell printf which buffer to be used. You can use your own buffer and control the contents.
However, this is the wrong approach for 2 reasons.
1st, it won't save you work compared to printf(), fwrite() and putchar().
2nd, and more important, even these functions won't help you. From your comment it's clear that you want to manipulate a character on the screen, for example, replace a '.' (empty floor) by a D (Dragon) when that Dragon approaches. You can't do this by manipulating the output buffer of printf(). Once the '.' is displayed, the output buffer has been flushed to the terminal, and if you manipulate that buffer, it has no effect. The terminal has received a copy of that buffer, and has displayed what the data in the buffer instructed it to display. In order to change what is displayed, you have to send new commands.
And this is exactly what ncurses does for you. It keeps track of the state of the terminal, the current content, the curser position and all the nasty details, like, how to make a character appear bold.
You won't succeed with printf. That's hopeless. You need to learn what ncurses can do for you, and then everything else is easy.
TLDR: use ncurses
This answer focuses on the why?
Why?
There probably is a way to modify the buffer used by the terminal emulator on your system, given that you have sufficient priviledges to write into respective memory and maybe even modify other system resources, as required.
As terminals historically have been distinct, isolated, physical devices rather than beeing conceptually emulated in software, you couldn't access them in any way other than sending them data.
(I mean, you could always print a message locally, to instruct a human to take a screwdriver and physically mess around with the physical terminal device, but that's not been the way how humans wanted to solve the contemporary issue of "how do I change the cursor position and rewrite characters on my (and potentially any other connected) terminal?").
As others have pointed out, most physical terminals have (at some point) been built to give special meaning to certain input sequences, instead of printing them, which makes them escape sequences in this context, according to how wikipedia.org defines them, that is.
A behavioral convention in how to respond to certain input sequences emerged (presumably for the sake of interoperability or for reasons of market predominance)and got standardized as ANSI escape codes.
Those input sequences survived the transition from physical termial devices to their emulated counterparts and even though you could probably manipulate the terminal emulator's memory using system calls, libraries such as ncurses allow you to easily make use of said ANSI escape codes in your console application.
Also, using such libraries is the obvious solution to make your application work remotely:
Yes, technically, you could ssh into another system (or get access in any other more obscure way that works for you),and cause system calls or any other event that would interfere with the terminal emulator in the desired way.
Firstly, I doubt most users would want to grant you priviledge to modify their terminal emulator's memory merely to enjoy your text adventure.
Also, interoperability would reduce, as you couldn't easily support that one user, who still has a VT100 and insists on using it to play your game.

Get trigger from console in C++

I am writing an application for a robot.
The required UI for the application is described in the pseudo-code below:
while(true){
if (spacebar is not pressed){
//do something
}
else{
sleep(1); //wait for a second
}
}
If I use cin or some other console input reading function then it will wait for user to press something. How do I ensure that it does not wait to get any input?
I am using Ubuntu. But I do not want it to be OS-specific.
Answers here seem to be OS specific.
Terminal Level input
What you are asking for is fairly close to the hardware (key-press / key-release) compared to the "standard input/output" stream concepts. So your implementation would have to be OS specific. Having said that the library to use is curses[1] which has been around for a long time and is standard on a lot of Un*x platforms. The GNU ncurses flavor compiles for pretty much all of them, it is a standard install in almost all Linux environments, and where it isn't installed by default you can find it. It also works well in Windows (cygwin), os/2 and a bunch of embedded systems etc. so you should be able to write a fairly portable software using curses that does what you want.
It's not too clear what you're asking for. In the if, is the
condition based on whether a space character has been entered,
or whether the user is currently holding down the space bar? In
the first case, you need something like curses (a portable
library which does gets each character as it was entered,
without echo). In the second, I don't think that there is
a portable solution. Even non-portably, you might not be able
to get it if your program is reading from a terminal window
(e.g. xterm); this sort of information is typically only present
as window events, when you created the window in your program.

Windows version of wcswidth_l

I have some text to write to the Windows console that I need to know the real width of in columns. wcswidth_l seems to be the best option on platforms that have it (though mbswidth_l() would be better since I have no desire to use wchar_t, but for some reason it doesn't exist). But in addition to other platforms, I need something that works on Windows. Although it's unlikely that there's a portable solution, I don't know of any solution at all on Windows. I think the console has an API for getting cursor position and such, so I could write the text out and check the change in position. That would be accurate I guess, but writing out extra output isn't acceptable at all.
How does one go about getting the column width of a string or character on Windows?
Edit:
wcswidth_l returns the number of console columns used to display a string. Some characters take up one column and others, e.g. japanese characters, take up two.
As an example the 'column width' of "a あ" is four. 'a' is one, ' ' is one, and 'あ' is two. (Assuming the console is set up to actually display non-ascii characters that is). Also it'd be nice if the API supports strings using codepage 65001 (UTF-8).
First of all, the Windows Console API is located here.
Secondly, is the function you're looking for GetConsoleFontSize?
I'll try to quickly type an example in a second.
EDIT: Here you go. Forgive me if it there's a small error. I actually found it was even easier. GetCurrentConsoleFont fills in a COORD structure on the way to you getting the index to pass to GetConsoleFontSize, so step saved :)
#define _WIN32_WINNT 0x0501 //XP, 0x0601=windows 7
#include <windows.h>
int main()
{
HANDLE hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFO cfi;
GetCurrentConsoleFont (hStdOutput, FALSE, &cfi);
//cfi.dwFontSize.X == x size
//cfi.dwFontSize.Y == y size
}
EDIT:
If you don't mind invisible output, you can use CreateConsoleScreenBuffer to pretty much have an invisible console window at your command while leaving yours unaffected. GetConsoleScreenBufferInfoEx will tell you the cursor position, at which point you can use WriteConsole to write to your buffer (invisibly), and check the cursor location again versus the number of characters actually written. Note that checking the cursor location beforehand would not require clearing the screen to use this method.
If you cannot afford to do extra output, visible or invisible, I'm not sure there really is a possibility.
Portable approach
Since width of characters depends more on characters themselves rather than the system on which they are displayed (ok, there might be excepetions, but they should be rather rare), one can use separate function to do that (on Windows too). This requires Unicode characters as it makes it much easier to analyze width of strings, but one for sure can write a wrapper to convert between encodings.
Available implementation
Here is suitable and portable implementation, which one can plug in into his application and fallback to use it on Windows.

Update and multiple console windows

I want to write a simple c++/c console app, to show my process 1% 2%.
for now, i print it line by line like
finished 1%
finished 2%
and etc
How can I just update percentage x% without printing a new line?
Also, I want to open two console windows one show messages one show the process as above. How do I open another console window?
On most-all terminals, you can print the ASCII carriage return '\r' (value 13 decimal) to return the cursor to the left of the current line, allowing you to overwrite the previous value. Or, you can send backspaces ('\b', ASCII 8) to move a single character left. Neither will automatically remove content already displayed, but you can always overwrite anything you no longer want to see with some spaces. Alternatively, you can use control codes supported by your particular console (e.g. vt100, vt220...), which will probably have more advanced features such as "clear-to-end-of-line". Many libraries are available to detect the terminal type and use codes it supports, or synthesize advanced operations from many simpler ones where necessary: on Linux and UNIX, the ncurses library is a good choice.
C++ has no concept of console windows. Opening a second window depends a lot on the operating system you're using, and perhaps the graphics library, neither of which you specified. On any OS though, you can have your application write some messages into a file, then inspect that file from another window that you open yourself. On Linux/UNIX, the utility "less" is great for inspecting log files - as well as showing you the contents at the time you ran less, you can ask it to "follow" new data as it is written into the file.
On windows you can move the cursor to any location on the screen, then start printing from there:
COORD c;
c.X = x; c.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
Of course, you need to include windows.h
You can update your progress message in several ways. You can print out backspace characters to move the cursor to the left and then write over the old output. If your console supports ANSI escape sequences, you can use an escape sequence to blank out the line and re-draw it.
The best technique to use will probably depend on the console you are using (different consoles support different things). What platform are you using, and what console?
It seems that you're talking about Windows console apps.
Each Windows process is associated with at most one console window.
It you want two console windows then you can start another process and pipe output to it, or communicate with it via sockets or Windows "mailslots" or whatever.