For example, that when you press "Esc", the application ends.
Asked
Active
Viewed 1.3k times
3 Answers
9
Here is a workaround for linux. Using these posts
Capture characters from standard input without waiting for enter to be pressed https://stackoverflow.com/a/912796/2699984
I've made it like this:
ConsoleReader.h
#ifndef CONSOLEREADER_H
#define CONSOLEREADER_H
#include <QThread>
class ConsoleReader : public QThread
{
Q_OBJECT
signals:
void KeyPressed(char ch);
public:
ConsoleReader();
~ConsoleReader();
void run();
};
#endif /* CONSOLEREADER_H */
ConsoleReader.cpp
#include "ConsoleReader.h"
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
static struct termios oldSettings;
static struct termios newSettings;
/* Initialize new terminal i/o settings */
void initTermios(int echo)
{
tcgetattr(0, &oldSettings); /* grab old terminal i/o settings */
newSettings = oldSettings; /* make new settings same as old settings */
newSettings.c_lflag &= ~ICANON; /* disable buffered i/o */
newSettings.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &newSettings); /* use these new terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void)
{
tcsetattr(0, TCSANOW, &oldSettings);
}
/* Read 1 character without echo */
char getch(void)
{
return getchar();
}
ConsoleReader::ConsoleReader()
{
initTermios(0);
}
ConsoleReader::~ConsoleReader()
{
resetTermios();
}
void ConsoleReader::run()
{
forever
{
char key = getch();
emit KeyPressed(key);
}
}
And then just start new thread to read keys:
ConsoleReader *consoleReader = new ConsoleReader();
connect (consoleReader, SIGNAL (KeyPressed(char)), this, SLOT(OnConsoleKeyPressed(char)));
consoleReader->start();
*UPDATED (added restoring terminal settings on quit)
-
`consoleReader->start();` -- do you mean `run()`? – Anon Dec 06 '18 at 19:31
-
I used this in my project and if worked just fine. Please note that key codes depend on the type of terminal you are using. This may also change if you connect via SSH instead of using a terminal session. – Thomas H. Schmidt Feb 12 '19 at 15:44
7
If you need only 'quit' maybe the following snippet will help (c++11 and qt5 required):
#include <iostream>
#include <future>
#include <QCoreApplication>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication application(argc, argv);
bool exitFlag = false;
auto f = std::async(std::launch::async, [&exitFlag]{
std::getchar();
exitFlag = true;
});
QTimer exitTimer;
exitTimer.setInterval(500);
exitTimer.setSingleShot(false);
QObject::connect(&exitTimer,
&QTimer::timeout,
[&application,&exitFlag] {
if (exitFlag)
application.quit();
});
exitTimer.start();
std::cout << "Started! Press Enter to quit...";
int ret = application.exec();
std::cout.flush();
f.wait();
return ret;
}

vrogach
- 613
- 1
- 13
- 16
-
works well! could you explain why need `f.wait()` after `exec()`? – spartawhy117 Jul 24 '17 at 09:36
-
It's the explicit syncronization point where async() thread joins safely. The 'f' object std::future destructor may not explicitly block until tread joins (that needs exploration) – vrogach Jul 26 '17 at 11:42
-
1It have to add `std::cout.flush();` before `int ret = application.exec();` line. – B0FEE664 Sep 16 '20 at 14:03
5
Qt doesn't handle console events, it can just read \n
-terminated lines from the console.
You need to use native APIs or other libraries (curses).

alexisdm
- 29,448
- 6
- 64
- 99