I am currently working on a simple console application that is to become a text-based RPG game based on economy. I have an 80x20 (character cells) window that will work as my display.
I have been experimenting with the FillConsoleOutputCharacter() API function, which seems to work as desired for clearing the console.
Before I use the function, I have simple output using wcout to display certain characteristics, such as the screen buffer size and the window size; but after outputting with FillConsoleOutputCharacter(), I notice that wcout does not output as it should.
I have the API function nested in another function named clearConsole(), and have noticed that output using wcout works as it should after leaving the function, but not after the call to FillConsoleOutputCharacter() (within the function).
Here is the function:
void clearConsole(HANDLE screen)
{
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
DWORD dwConsoleSz;
if(!GetConsoleScreenBufferInfo(screen, &bufferInfo))
{
return;
}
dwConsoleSz = bufferInfo.dwSize.X * bufferInfo.dwSize.Y; /* This should be equivalent to the number of character cells in the buffer. */
/* Now we fill the entire screen with blanks. */
if(!FillConsoleOutputCharacter(
screen,
L' ',
dwConsoleSz,
cursorHome,
&cCharsWritten
));
{
return;
}
/* Then we get the current text attribute (maybe unnecessary?) */
if(!GetConsoleScreenBufferInfo(screen, &bufferInfo)) /* Perhaps the ScreenBuffer needs to be set again, see SetConsoleCursorPosition. */
{
return;
}
/* And set the buffer's attributes accordingly. */
if(!FillConsoleOutputAttribute(
screen,
bufferInfo.wAttributes,
dwConsoleSz,
cursorHome,
&cCharsWritten
))
{
return;
}
if(!SetConsoleCursorPosition(screen, bufferInfo.dwCursorPosition))
/*Research is needed regarding this function as it does not seem to move the cursor. */
{
wcout << L"SetConsoleCursorPosition failed. Error Code: " << GetLastError();
system("pause");
}
wcout << L"Screen Buffer Size: " << bufferInfo.dwSize.X << L',' << bufferInfo.dwSize.Y << L'\n' << L"Cursor Position: " <<
bufferInfo.dwCursorPosition.X << L',' << bufferInfo.dwCursorPosition.Y << L'\n' <<
L"Buffer Top X: " << bufferInfo.srWindow.Left << L' ' << L"Buffer Top Y: " << bufferInfo.srWindow.Top << L'\n' << L"Buffer Bottom X : " << bufferInfo.srWindow.Right << L' ' << L"Buffer Bottom Y: " << bufferInfo.srWindow.Bottom << L'\n';
wcout << L"hello from clearConsole" << L'\n';
/* wcout stops working from within this function after FillConsoleOutputCharacter is
called. But for some odd reason it begins working again after the function ends.
*/
Sleep(1000);
return;
}
What could be the cause for this?
I have experimented with moving the wcout lines around within the nesting function, and have seen that it works before the call to the API function, but not after. A strange malfunction. Flushing wcout (or the output stream) does not solve the issue, either.
Setting the cursor back to (0,0) does not seem to place the cursor back at the top left corner of the console, either. screen is a global variable set to STD_OUTPUT_HANDLE.
EDIT: Also, trying to set the cursor back to (0,0) using a global COORD object cursorHome in the call to SetConsoleCursorPosition() before writing to output does not seem to work, either.
EDIT: Setting the cursor's position after the call to clearConsole() works as well. What could be the cause of this strange behavior?
After multiple tests. It is caused by a very minor error - the ; after FillConsoleOutputCharacter().
/* Now we fill the entire screen with blanks. */
if(!FillConsoleOutputCharacter(
screen,
L' ',
dwConsoleSz,
cursorHome,
&cCharsWritten
)); // <-- HERE
{
return;
}
It cuts off the front and back connection and destroys the logic. It means that whatever value is returned by FillConsoleOutputCharacter() has nothing to do with the content in { }.
Just delete it.
Related
I need to print to console some output with color content. Is it possible to do in windows atomically? In Linux there is ansi colors support and it is really very convenient to do complex colored sentences. What about windows? I can do the following:
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
printf(" this is how it starts ");
SetConsoleTextAttribute(hConsole, 10);
printf("YES, it should be green ");
SetConsoleTextAttribute(hConsole, 0);
printf("back to standard color\n");
It seems to me that in asynchronous app this 3 printf will not print text at the same line in console. Here comes 2 solutions in my mind:
1) Use mutex for syncing all console output so as all messages appear sequentially. Seems an overkill solution for such problem.
2) Use some method to stop console output for a while, print colored line and then start output again.
So, my concern is getting colored line without breaks made by other asynchronous output. Is it possible in windows and what is the best approach?
As #eryksun said, use WriteConsoleOutput instead of printf/std::cout.
This is the same as any graphical application. Only one thread does all the writing. It has a queue which contains a list of strings and attributes. When a thread wishes to print something, it pushes the string and the relevant attribute into the queue. Before printing the writing thread sets the attribute and then prints the string.
You will need to implement your own thread-safe queue. Mine are normally low volume outputs so I use an array of 256 with a uint8_t counter and atomic markers. There is no boundary checking: uint8_t wraps back to 0 after 255. Circular queues work quite well.
You can create a very simple class to do the writing. I normally use something like this. Scribbler is the class that does the writing to the screen
class COut : public std::ostringstream
{
Scribbler* writer;
WORD attr;
public:
COut(WORD in_attr)
{
attr = in_attr;
writer = Scribbler::Me();
}
COut& operator << (std::ostream&(*f)(std::ostream&))
{
if (f == std::endl)
{
*this << "\n";
writer->Push(attr, str());
str("");
}
else
{
*this << f;
}
return *this;
}
template <typename TT>
inline COut& operator << (const TT& t)
{
(*(std::ostringstream*) this) << t;
return *this;
}
};
This can be used like std::cout and it will do everything you can do with std::cout. Alternatively, you can write a variant of printf but it isn't that simple when you get into the depths of passing std::arg all over the place.
The thread wanting yellow output would do something like
COut yout(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
...
yout << "Yellow, yellow dirty fellow" << std::hex << std::setfill('0') << std::setw(4) << 25 << std::endl;
The thread wanting magenta output would do
COut mout(FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
...
mout << ... << std::endl;
Nothing gets printed until a std::endl is issued. You can get quite creative with this with different threads writing to different scrollable parts of the screen using SetConsoleWindowInfo. It will work as long as there is only one thread that does the writing. All the other threads just tell it where to write the output and its colour attributes.
I was wondering if it was possible to replace the text "[1] example1 [2] example2" after keyboard input with "example1extended" that's already on the screen.
Something like system("CLS"); but for only a certain line of text.
int main() //just an example
{
int ans;
std::cout << "[1] example1 [2] example2" << std::endl;
std::cout << "enter a choice: ";
std::cin >> ans;
if (ans == 1)
{
std::cout << "example1extended" << std::endl;
}
}
At first: There is no "screen" for c++. There is only input and output to "something" which is a typically a terminal. But how this terminal behaves is not part of c++ standard and as this not portable. So the results with different terminals and especially on different OS are different.
If you are working with a terminal which have e.g. VT100 support, you can use the special characters to control the cursor and erase chars on the terminal screen. https://en.wikipedia.org/wiki/VT100 https://www.csie.ntu.edu.tw/~r92094/c++/VT100.html
There are hundreds of libraries arround which are dealing with such kind of terminal ( emulators ).
There's no platform independent way of doing that but since you mentioned system('cls') I assume you are on Windows.
Windows has the Console Functions API which is a set of utility functions used for manipulating the console. You have 2 options here:
Set the cursor's position and overwrite it with spaces:
#include <windows.h>
..
auto consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coordsToDelete = { row, col }; // the coordinates of what you want to delete
// Move the current cursor position back. Writing with std::cout will
// now print on those coordinates
::SetConsoleCursorPosition(consoleHandle, position);
// This will replace the character at (row, col) with space.
// Repeat as many times as you need to clear the line
std::cout << " ";
Alternatively, you can get the entire console buffer and directly modify it:
#include <windows.h>
..
auto consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
// Get a handle to the console buffer
GetConsoleScreenBufferInfo(consoleHandle, &csbi));
DWORD count;
COORD coords = { row, 0 };
DWORD cellCount = /* the length of your row */;
// Write the whitespace character to the coordinates in cellCount number of cells
// starting from coords. This effectively erases whatever has been written in those cells
FillConsoleOutputCharacter(
consoleHandle,
(TCHAR) ' ',
cellCount,
coords,
&count);
I have the following code (implemented in the mouseReleaseEvent) to detect when the user has selected lines of text:
QTextCursor cursor = this->textCursor();
int start = cursor.selectionStart();
int end = cursor.selectionEnd();
if(!cursor.hasSelection())
return; // No selection available
qWarning() << "start: " << start << " end: " << end << endl;
the problem is: I need the line numbers where the selection begins and ends. I've been struggling with blocks and solved nothing, can you please give me a clue?
It is possible, that it isn't the best solution, but it seems to work for me. The variable selectedLines will contain, how many lines are selected.
QTextCursor cursor = ui->plainTextEdit->textCursor();
int selectedLines = 0; //<--- this is it
if(!cursor.selection().isEmpty())
{
QString str = cursor.selection().toPlainText();
selectedLines = str.count("\n")+1;
}
I hope, that it will be helpful :)
I see easy way to use chain of 2 QTextCursor methods - setPosition and blockNumber.
QTextCursor cursor = this->textCursor();
int start = cursor.selectionStart();
int end = cursor.selectionEnd();
if(!cursor.hasSelection())
return; // No selection available
cursor.setPosition(start);
int firstLine = cursor.blockNumber();
cursor.setPosition(end, QTextCursor::KeepAnchor);
int lastLine = cursor.blockNumber();
qWarning() << "start: " << firstLine << " end: " << lastLine << endl;
UPD:
cursor.setPosition(start);
cursor.block().layout()->lineForTextPosition(start).lineNumber();
// or
cursor.block().layout()->lineAt(<relative pos from start of block>).lineNumber();
Set position to begin of selection. Get current block, get layout of block and use Qt API for getting line number. I doesn't know which line number returned is absolute for whole document or for layout. If only for layout, you need some additional process for calculate line numbers for previous blocks.
for (QTextBlock block = cursor.block(). previous(); block.isValid(); block = block.previous())
lines += block.lineCount();
I have a QByteArray to store data received from a GPS, which is part binary and part ASCII. I want to know for debug proposals know what's being received, so I'm writing a qDebug like this:
//QByteArray buffer;
//...
qDebug() << "GNSS msg (" << buffer.size() << "): " << buffer;
And I get messages like this at console:
GNSS msg ( 1774 ): "ygnnsdgk...(many data)..PR085hlHJGOLH
(more data into a new line, which is OK because it is a new GNSS sentence and
probably has a \n at the end of each one) blablabla...
But suddenly I get a new print iteration. Data has not been erased yet, it has been appended. So new message size its for example 3204, bigger than the previous print obviously. But it prints exactly the same (but with the new size 3204 between brackets). No new data is printed, just the same as the previous message had:
GNSS msg ( 3204 ): "ygnnsdgk...(many data)..PR085hlHJGOLH
(more data into a new line, which is OK because it is a new GNSS sentence and
probably has a \n at the end of each one) blablabla...
I guess qDebug stops printing because it has a limit, or because it reaches a terminating character or something like that, but I'm only guessing.
Any help or explanation for this behaviour?
Solution / workaround:
Indeed, the qDebug() output of QByteArray gets truncated at a '\0' character. This doesn't have something to do with the QByteArray; you even can't ever output a '\0' character using qDebug(). For an explanation see below.
QByteArray buffer;
buffer.append("hello");
buffer.append('\0');
buffer.append("world");
qDebug() << "GNSS msg (" << buffer.size() << "): " << buffer;
Output:
GNSS msg ( 11 ): "hello
Even any following arguments are ignored:
qDebug() << "hello" << '\0' << "world";
Output:
hello
You can work around this "problem" by replacing the special characters in your byte array before debugging them:
QByteArray dbg = buffer; // create a copy to not alter the buffer itself
dbg.replace('\\', "\\\\"); // escape the backslash itself
dbg.replace('\0', "\\0"); // get rid of 0 characters
dbg.replace('"', "\\\""); // more special characters as you like
qDebug() << "GNSS msg (" << buffer.size() << "): " << dbg; // not dbg.size()!
Output:
GNSS msg ( 11 ): "hello\0world"
So why is this happening? Why can't I output a '\0' using qDebug()?
Let's dive into the Qt internal code to find out what qDebug() does.
The following code snippets are from the Qt 4.8.0 source code.
This method is called when you do qDebug() << buffer:
inline QDebug &operator<<(const QByteArray & t) {
stream->ts << '\"' << t << '\"'; return maybeSpace();
}
The stream->ts above is of type QTextStream, which converts
the QByteArray into a QString:
QTextStream &QTextStream::operator<<(const QByteArray &array)
{
Q_D(QTextStream);
CHECK_VALID_STREAM(*this);
// Here, Qt constructs a QString from the binary data. Until now,
// the '\0' and following data is still captured.
d->putString(QString::fromAscii(array.constData(), array.length()));
return *this;
}
As you can see, d->putString(QString) is called (the type of d is the internal private class of the text stream), which calls write(QString) after doing some padding for constant-width fields. I skip the code of putString(QString) and directly jump into d->write(QString), which is defined like this:
inline void QTextStreamPrivate::write(const QString &data)
{
if (string) {
string->append(data);
} else {
writeBuffer += data;
if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
flushWriteBuffer();
}
}
As you can see, the QTextStreamPrivate has a buffer. This buffer is of type QString. So what happens when the buffer is finally printed on the terminal? For this, we have to find out what happens when your qDebug() statement finishes and the buffer is passed to the message handler, which, per default, prints the buffer on the terminal. This is happening in the destructor of the QDebug class, which is defined as follows:
inline ~QDebug() {
if (!--stream->ref) {
if(stream->message_output) {
QT_TRY {
qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
} QT_CATCH(std::bad_alloc&) { /* We're out of memory - give up. */ }
}
delete stream;
}
}
So here is the non-binary-safe part. Qt takes the textual buffer, converts it to "local 8bit" binary representation (until now, AFAIK we should still have the binary data we want to debug).
But then passes it to the message handler without the additional specification of the length of the binary data. As you should know, it is impossible to find out the length of a C-string which should also be able to hold '\0' characters. (That's why QString::fromAscii() in the code above needs the additional length parameter for binary-safety.)
So if you want to handle the '\0' characters, even writing your own message handler will not solve the problem, as you can't know the length. Sad, but true.
I can't get this to work right. This should press left for 1 second then wait 10 seconds, then right 1 second, etc.:
keybd_event(0x25, 0xCB, 0, 0); // press left
cout << "Ldown\n"; // so i know it worked
Sleep(1000); // hold it for 1sec
keybd_event(0x25, 0xCB, KEYEVENTF_KEYUP, 0);// let go of the key
cout << "Lup\n"; // so i know i let go
Sleep(10000); // Sleep for 10secs
keybd_event(0x27, 0xCD, 0, 0); // press right
cout << "Rdown\n"; // so i know i pressed right
Sleep(1000); // sleep 1sec
keybd_event(0x27, 0xCD, KEYEVENTF_KEYUP, 0);// let go of the key
cout << "Rdown\n"; // so i know i let go.
This is in a loop but it wont do anything :( Unless I close the program before the key is let go, then it will just keep the key down until I press the key again.
I know you can use only one key code if you want but I need to use both.
So what am I missing?
The code seems to work for me. I cleaned it up a bit (no magic numbers!, use MapVirtualKey, helper functions, etc.):
#include <iostream>
#include <windows.h>
// for key pushing
BYTE scan_code(DWORD pKey)
{
const DWORD result = MapVirtualKey(pKey, MAPVK_VK_TO_VSC);
return static_cast<BYTE>(result);
}
void press_key(DWORD pKey)
{
keybd_event(static_cast<BYTE>(pKey), scan_code(pKey), 0, 0);
}
void release_key(DWORD pKey)
{
keybd_event(static_cast<BYTE>(pKey), scan_code(pKey), KEYEVENTF_KEYUP, 0);
}
// for testing
#define PRESS(x) press_key(x); std::cout << "Press: " #x << std::endl
#define RELEASE(x) release_key(x); std::cout << "Release: " #x << std::endl
// test
int main(void)
{
for (;;)
{
PRESS(VK_LEFT);
Sleep(10); // hold it for 1/100'th of a second
RELEASE(VK_LEFT);
Sleep(1000); // wait for a second
PRESS(VK_RIGHT);
Sleep(10); // hold it for 1/100'th of a second
RELEASE(VK_RIGHT);
Sleep(1000); // wait for a second
}
}
I tested by opening Notepad, typing a bunch of characters, then ran the program. The caret moved back and forth. How are you testing it?
How are you measuring "doesn't do anything"? Is it just that no output appears? Use std::endl to end your lines, as GMan does, instead of "\n", because endl performs a flush in addition to outputting a newline character.