So basically I just want to read characters from the user and make my code know that when user types a defined combination (say, CTRL+F - but without confirming with Enter, for exmaple), it's the end of the input. How can I do that? I only know how to read characters with enter and comparing their ASCII's...
EDIT
Reading through your question again, I realize that I misinterpreted your question. I'll leave this since it might still be useful to you or others.
What you're asking for doesn't have to do much with reading characters. In fact, CTRL is not a character at all. You're basically just checking for key pushes. Handling this kind of input is platform dependent, and even on a single platform, multiple methods will exist. One way to do it for windows is by using GetAsyncKeyState. This function will check whether a specified key is being pushed right now. Note that it doesn't 'remember' input, so you'll have to check this function many times per second to register all user input.
You supply the function with a single argument specifying the key of which you want to check the state. A list of all key codes can be found here
Example:
#include <iostream> //for output
#include <windows.h> //for GetAsyncKeyState
int main()
{
while(true)
{
if( GetAsyncKeyState(VK_CONTROL) ) //CTRL-key is pressed
{
if( GetAsyncKeyState( 0x46 ) ) //F-key is pressed
std::cout << "CTRL-F is pressed" << std::endl;
if( GetAsyncKeyState( 0x58 ) ) //X-key is pressed
break;
}
}
std::cout << "CTRL-X was pressed, stopping.." << std::endl;
}
This example will continuously check if CTRL-F is being pushed and if so write output, until CTRL-X is pressed.
The Windows system call ReadConsoleInput allows you to read console input directly. You may want to wrap that call into a function that just extracts the essential data from the several parameters of the ReadConsoleInput function. You can write a function to check if there is any input using GetNumberOfConsoleInputEvents.
try
#include <conio.h>
#include <iostream>
using namespace std;
int main()
{
bool keepGoing = true;
char key = ' ';
while (keepGoing){
cout << "Enter a key" << endl;
while(_kbhit()){
key = _getch();
cout << "You entered: " << key << endl;
}
}
}
then specify delimiter when to end loop.
if on linux curses are available. there is also a getch function. you should use curses if you aim for cross platform compatibility. ncurses library functions are similar to ones in conio.h.
ncurses tutorial
Related
Normally c/cpp string displayed in console only allows user to type after it.
Is there any simple way to let user to type in the middle of the output string, e.g fill in the blank:
Mr ____ is the teacher.
std::cout can print it easily, but how to let user type directly in the blank with simple code and read it? And e.g. if the name is long the move the printed character to the right?
You're looking for controlling a console/terminal. Neither of the languages you ask about has any notion of that -- they both only know streams of input and output. This is a simple abstraction, input and output are done character by character, in sequence. Input doesn't have to come from a keyboard, output doesn't have to be a screen or terminal ...
Controlling the contents of a screen is very platform-dependent. If you are on windows, the windows API provides a bunch of functions for controlling a console.
If you want to do something cross-platform, have a look at curses. There are implementations for many platforms, like ncurses (often used on *nix systems) and pdcurses (which is quite good for windows) and they all provide the same interface.
To learn about curses programming, the NCURSES Programming HOWTO is a good start. Just replace #include <ncurses.h> with #include <curses.h> so your code isn't tied specifically to ncurses but works with any curses implementation.
Yes, you can absolutely do this (I mean, ever played snake? All games were on terminals back then, and your problem is much simpler than writing a game).
A trick is using \r, which is a carriage return. That character will slide you back to the start of the line, allowing you to overwrite the previous string. This is commonly used for loading animations like
[---]
[=---]
[==-]
[===]
To prevent forcing the user to hit enter before sending data, I'll show a Linux/Mac solution.
system("/bin/stty raw"); // Get keystrokes immediately, #include <stdlib.h>
string s;
char c;
cout << "Mr _ is the teacher." << flush;
while( c = getchar() ) { // #include <stdio.h>
if( c == 3 ) // CTRL+C
exit(1);
if( c == 13 ) { // Newline
cout << endl;
break;
}
if( c == 127 ) { // Backspace
if( s.size() > 0 )
s.pop_back();
} else {
s += c;
}
cout << "\r"; // Reset the cursor
cout << "Mr " << s << "_ is the teacher. " << flush; // Spaces to cover invalid backspace character
cout << "\r"; // Reset the cursor
cout << "Mr " << s << "_ is the teacher." << flush;
}
system("/bin/stty cooked"); // Go back to buffered input
This can be done in Windows by importing #include<conio.h>, and then using getch() instead of getchar(). (You don't need any stty system commands)
Make sure to use your platform-specific #ifdef's to make your code portable!
For anybody else finding this question, this can be accomplished with the kbhit() function in the conio.h library. Just insert !kbhit() where I put SOMETHING and it will loop correctly, I am looking for a way to do this without a library, however.
I'm a beginner trying to create a simple animation in the console. The animation would have the word UP going up the right hand of the console and the word DOWN going down the right hand side. So far I have gotten the animation to complete one iteration of this, but I'm trying to make it so that it repeats and it looks like the texts wraps back to the top or bottom and does it again until the user presses the ENTER key.
My book (I'm self teaching from a textbook) makes it seem that its possible without any specific libraries except for iostream and windows.h but help that includes library functions is welcome too, it is a learning experience after all. Thanks a ton!
A little explanation of the code would be that I set the coordinates of the UP and DOWN starting positions and then move the cursor, delete the previous line it was on with a space and then increment two and put a new word. I would guess that I could use a second while loop to somehow check if the ENTER key has been pressed.
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
COORD upPos = {20,28};
COORD downPos = {50, 0};
char endState;
while ( SOMETHING )
{
COORD upPos = {20,28};
COORD downPos = {50, 0};
while (upPos.Y >=0)
{
SetConsoleCursorPosition(screen,upPos);
cout << "UP" << endl;
upPos.Y++;
SetConsoleCursorPosition(screen,upPos);
cout << " " << endl;
upPos.Y -=2;
SetConsoleCursorPosition(screen,downPos);
cout << "DOWN" << endl;
downPos.Y--;
SetConsoleCursorPosition(screen,downPos);
cout << " " << endl;
downPos.Y+=2;
Sleep(100);
}
}
}
Your best bet is to create a custom "GetAsyncKeyState" function that will use #IFDEF for windows and linux to choose the appropriate GetAsyncKeyState() or equivalent. For ex
if (GetAsyncKeyState(VK_RETURN))
{
exit = true;
}
With C++ is it possible to give the user a default value with the Cin statement, then have them backspace what they want to change? For instance: I give the user an option to change a string name, I output the name to the screen: "John Doe" and they can backspace to change the name to "John Smith".
For features like this and a lot more, take a look at GNU Readline or one of its workalikes. It's basically a library for applications to support command-line editing with familiar features like up-arrow to repeat previous commands, editing of those previous commands, and yes, you can customize the text presented to the user who can then edit it with the same keystrokes one would use in the shell.
I might be crazy, but here's a plain Windows solution that works on Visual Studio 2012 Update 1. It simulates the characters you want entered, which should keep them in the input buffer until they're ready to be read, and then reads input, waiting for a newline.
#include <iostream>
#include <string>
#include <windows.h>
void InsertDefaultName(const std::string &def) {
HWND hwnd = GetConsoleWindow();
for (char c : def) {
SendMessage(hwnd, WM_CHAR, c, 0);
}
}
int main() {
std::cout << "Enter name: ";
std::string name;
InsertDefaultName("John Doe");
std::getline(std::cin, name);
std::cout << "You entered " << name << '\n';
}
It's worth noting that this might not work completely properly if the user is, say, holding down a key before it gets to the InsertDefaultName() function call. A more robust library is definitely better, but this is here if it works well enough for you without a whole new library.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to stop C++ console application from exiting immediately?
I am a newbie on C++. Following tutorials, my program selfkilled when it finished executing simple commands (like cout ans stuff). I discovered the get.cin() function that avoided that. However, anytime I use 'cin' commands to insert variables, the program selfkills just after receiving the input and executing the work. Is there a way to avoid that? thanks a lot!
The reason it quits when your program receives input, even though you are using std::cin.get() is because whenever cin reads input, there's a chance that some junk is left behind; when you call std::cin.get(), you will get that junk.
What you have to do is clear cin of any undesired data, such that std::cin.get() has nothing to read and is required to wait for new input.
...
std::cin.clear();
std::cin.get();
return 0;
A program doesn't "kill itself". It just exits when it has finished doing everything it was supposed to do (i.e. when you return from main).
It is up to you to set up your work environment so that you can see the output of a program. For example, if you are in Windows, you could open your own command line (run cmd) and run your program from there; or instruct your IDE to not close the terminal window after the program exits.
Your program doesn't kill itself after execution, it just ends it.
Simple example:
#include <iostream>
int main( int argc, const char* argv[] )
{
std::cout << "Hello, World" << std::endl;
return 0; // End of execution
}
In that example a small window opens then close very fast because the logic of the code says so, However in the next example:
#include <iostream>
int main( int argc, const char* argv[])
{
std::cout <<"Hello, World!" << std::endl;
std::cin.get();
return 0;
}
Your application will still be showing in the screen until you press enter key 'Return key' then it will exit.
In case you are using Windows Operating System, consider the next example:
#include <iostream>
int main( int argc, const char* argv[])
{
std::cout << "Hello, World!" << std::endl;
system("PAUSE");
return 0;
}
Please note that system("PAUSE") is in Windows only and won't run on other operating systems.
One more thing worth mentioning here, there are a lot of methods to use other that these, but I wrote the most common ones.
In some windowing systems, a console window is created when your program executes. When your program finishes, this console window disappears.
I always recommend the "pause" pattern to newbies:
cout << "Paused. Press ENTER to continue.\n");
cin.ignore(10000, '\n'); // Ignore until 100000 characters are entered or a newline is entered.
Sometimes, I make this into a function:
void Pause(void)
{
cout << "Paused. Press ENTER to continue.\n");
cin.ignore(10000, '\n'); // Ignore until 100000 characters are entered or a newline is entered.
}
Hope this helps,
std::cin.get() work well and its usage is pretty easy but it expect user to press return.
I used to end my program using ESC, so it won't work for me, so I use this
#ifdef _WIN32
std::system( "pause" );
#else
std::system( "read -n1 -r -p \"Press any key to continue...\"" );
#endif
It would print "Press any key to continue..." and continue execution with pressing any key so I can use my lovely ESC
Does anyone know how to make an event loop in c++ without a library? It doesn't have to be cross-platform, I'm on a Mac. Basically, I want the program to run and do nothing until the user presses the up arrow key, then the program will output "You pressed up" or something. All i can think of is having an infinite while or for loop and get input with cin, but I don't think cin can detect arrow keys and I believe it pauses the program until it reaches a '\n';
I would want it to look like this:
void RUN()
{
while(true)
{
// poll events and do something if needed
}
}
int main()
{
RUN();
}
I'm kinda sure it's possible without threads, and I've heard that this can be accomplished with fd_set or something, but I'm not sure how.
Any help would be really appreciated.
EDIT:
The program has to run in the background when there aren't any events. For example, Microsoft Word doesn't stop until the user presses a button, it keeps running. I want something like that, but command-line not GUI.
Since you're talking keyboard input, and not looking for a Mac look and feel, what you want is the UNIX way of doing it. And that is,
1) set the terminal in either raw or cbrk mode (I forget which).
2) now use read() to read single characters at a time.
3) temporarily echo the character read (as an int) so you can find what the up arrow key gives you.
As for the more general event loop question, where the only input device is the keyboard, you sit in a loop, and whenever a key is typed (in raw mode?) you call a routine with the value of the key typed. If you had more input devices, you would need multiple threads each could listen to a different device, putting what they find on a queues (with appropriate locking). The main loop would then check the queue and call a routine appropriately everytime something appears in it.
You can use ncurses and enable cbreak to get the raw input stream.
I've used a while loop with signal handlers. Like this incomplete snippet.
void getSomething()
{
std::cout << "Enter new step size: "; std::cout.flush();
std::cin >> globalVariable;
std::getchar(); // consume enter key.
}
void printCommands()
{
std::cout << "1: do something\n"
<< "q: quit\n"
<< "h: help\n"
<< std::endl;
}
void getCommand()
{
// Output prompt
std::cout << "Enter command ('h' for help): "; std::cout.flush();
// Set terminal to raw mode
int ret = system("stty raw");
// Wait for single character
char input = std::getchar();
// Reset terminal to normal "cooked" mode
ret = system("stty cooked");
std::cout << std::endl;
if (input == 'h') printCommands();
else if (input == '1') getSomething();
else if (input == 'q') {
g_next = true;
g_quit = true;
}
}
void
signalHandler(int signo)
{
if (signo == SIGINT) {
g_next = true;
} else if (signo == SIGQUIT) {
getCommand();
}
}
int main(int argc, char* argv[])
{
signal(SIGINT, signalHandler);
signal(SIGUSR1, signalHandler);
signal(SIGQUIT, signalHandler);
do {
// Stuff
} while (!g_quit);
exit(0);
}
The question has been updated to say "The program has to run in the background ... but command-line not GUI."
All traditional; *NIX shells that can put a program into the background also disconnect the program's standard input from the terminal, so AFAIK, this has become impossible.
This does not need to be Mac specific. The Mac supports *NIX mechanisms for reading characters from a keyboard.
AFAICT all the program is doing is waiting for a character, so it might as well block.
Normally the terminal device, tty (teletype!), is interpreting characters typed on the keyboard before your program can read them from standard input. Specifically the tty device normally buffers an entire line of text, and intercepts the rubout character (and a few others like CTRL+w) to edit the line of text. This pre-processing of characters is called a 'line discipline'
You need to set the tty device driver to stop doing that! Then you can get all of the characters the user types.
You change the device using ioctl or termios on the file descriptor.
Search for e.g. "ioctl tty line discipline raw" to understand the details, and find program examples.
You can set the terminal to 'raw' using the command line program stty.
Please read the stty man page because setting it back can be slightly tricky (NB: if you make a mistake it is often easier to kill the terminal, than try to fix it, because there is not echoing of anything you type)
It is possible that the up-arrow is not a single char, so it will require some byte-at-a-time decoding to avoid blocking at the wrong point in the input stream, i.e. if some input sequences are one character, and others two, or three characters, the decoding needs to happen at each byte to decide if there is a pending byte, or one too many read's might get issued, which would cause the program to block.