如何模拟“按任意键继续?”

我正在尝试编写一个 C + + 程序,当用户从键盘输入任何字符,它应该移动到下一行代码。

这是我的代码:

char c;


cin>>c;


cout<<"Something"<<endl;

但是这不起作用,因为只有当我输入一些字符然后按 ENTER 时,它才会移动到下一行。

或者

如果我用这个

cin.get() or cin.get(c)

当我按回车时,它移动到下一行指令。

但我想它移动到下一行的任何键盘上按下的键,这是怎么做到的呢?

178287 次浏览

To achieve this functionality you could use ncurses library which was implemented both on Windows and Linux (and MacOS as far as I know).

If you're on Windows, you can use kbhit() which is part of the Microsoft run-time library. If you're on Linux, you can implement kbhit thus (source):

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>


int kbhit(void)
{
struct termios oldt, newt;
int ch;
int oldf;


tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);


ch = getchar();


tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);


if(ch != EOF)
{
ungetc(ch, stdin);
return 1;
}


return 0;
}

Update: The above function works on OS X (at least, on OS X 10.5.8 - Leopard, so I would expect it to work on more recent versions of OS X). This gist can be saved as kbhit.c and compiled on both Linux and OS X with

gcc -o kbhit kbhit.c

When run with

./kbhit

It prompts you for a keypress, and exits when you hit a key (not limited to Enter or printable keys).

@Johnsyweb - please elaborate what you mean by "detailed canonical answer" and "all the concerns". Also, re "cross-platform": With this implementation of kbhit() you can have the same functionality in a C++ program on Linux/Unix/OS X/Windows - which other platforms might you be referring to?

Further update for @Johnsyweb: C++ applications do not live in a hermetically sealed C++ environment. A big reason for C++'s success is interoperability with C. All mainstream platforms are implemented with C interfaces (even if internal implementation is using C++) so your talk of "legacy" seems out of place. Plus, as we are talking about a single function, why do you need C++ for this ("C with classes")? As I pointed out, you can write in C++ and access this functionality easily, and your application's users are unlikely to care how you implemented it.

You can use the getchar routine.

From the above link:

/* getchar example : typewriter */
#include <stdio.h>


int main ()
{
char c;
puts ("Enter text. Include a dot ('.') in a sentence to exit:");
do {
c=getchar();
putchar (c);
} while (c != '.');
return 0;
}

I looked into what you are trying to achieve, because I remember I wanted to do the same thing. Inspired by Vinay I wrote something that works for me and I sort of understand. But I am not an expert, so please be careful.

I don't know how Vinay knows you are using Mac OS X. But it should work kind of like this with most unix-like OS. Really helpful as resource is opengroup.org

Make sure to flush the buffer before using the function.

#include <stdio.h>
#include <termios.h>        //termios, TCSANOW, ECHO, ICANON
#include <unistd.h>     //STDIN_FILENO




void pressKey()
{
//the struct termios stores all kinds of flags which can manipulate the I/O Interface
//I have an old one to save the old settings and a new
static struct termios oldt, newt;
printf("Press key to continue....\n");


//tcgetattr gets the parameters of the current terminal
//STDIN_FILENO will tell tcgetattr that it should write the settings
// of stdin to oldt
tcgetattr( STDIN_FILENO, &oldt);
//now the settings will be copied
newt = oldt;


//two of the c_lflag will be turned off
//ECHO which is responsible for displaying the input of the user in the terminal
//ICANON is the essential one! Normally this takes care that one line at a time will be processed
//that means it will return if it sees a "\n" or an EOF or an EOL
newt.c_lflag &= ~(ICANON | ECHO );


//Those new settings will be set to STDIN
//TCSANOW tells tcsetattr to change attributes immediately.
tcsetattr( STDIN_FILENO, TCSANOW, &newt);


//now the char wil be requested
getchar();


//the old settings will be written back to STDIN
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);


}




int main(void)
{
pressKey();
printf("END\n");
return 0;
}

O_NONBLOCK seems also to be an important flag, but it didn't change anything for me.

I appreciate if people with some deeper knowledge would comment on this and give some advice.

On Windows:

system("pause");

and on Mac and Linux:

system("read");

will output "Press any key to continue..." and obviously, wait for any key to be pressed. I hope thats what you meant

Also you can use getch() from conio.h. Just like this:

...includes, defines etc
void main()
{
//operator
getch(); //now this function is waiting for any key press. When you have pressed its     just     //finish and next line of code will be called
}

So, because UNIX does not have conio.h, we can simulate getch() by this code (but this code already written by Vinary, my fail):

#include <stdio.h>
#include <termios.h>
#include <unistd.h>


int mygetch( ) {
struct termios oldt,
newt;
int            ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}

You could use the Microsoft-specific function _getch:

#include <iostream>
#include <conio.h>
// ...
// ...
// ...
cout << "Press any key to continue..." << endl;
_getch();
cout << "Something" << endl;

This works on a Windows Platform: It Uses the Microprocessor registers directly and can be used to check key press or mousebutton

    #include<stdio.h>
#include<conio.h>
#include<dos.h>
void main()
{
clrscr();
union REGS in,out;
in.h.ah=0x00;
printf("Press any key : ");


int86(0x16,&in,&out);
printf("Ascii : %d\n",out.h.al);
char ch = out.h.al;
printf("Charcter Pressed : %c",&ch);
printf("Scan code : %d",out.h.ah);
getch();
}

There is no completely portable solution.

Question 19.1 of the comp.lang.c FAQ covers this in some depth, with solutions for Windows, Unix-like systems, and even MS-DOS and VMS.

A quick and incomplete summary:

  • You can use the curses library; call cbreak() followed by getch() (not to be confused with the Windows-specific getch()function). Note that curses generally takes control of the terminal, so this is likely to be overkill.
  • You might be able to use ioctl() to manipulate the terminal settings.
  • On POSIX-compliant systems, tcgetattr() and tcsetattr() may be a better solution.
  • On Unix, you can use system() to invoke the stty command.
  • On MS-DOS, you can use getch() or getche().
  • On VMS (now called OpenVMS), the Screen Management (SMG$) routines might do the trick.

All these C solutions should work equally well in C++; I don't know of any C++-specific solution.

Just use the system("pause"); command.

All the other answers over complicate the issue.

In windows, this short program accomplishes the goal: getch pauses the console until a key is pressed (https://www.geeksforgeeks.org/difference-getchar-getch-getc-getche/)

#include<iostream.h>
#include<conio.h>


using namespace std;


void  check()
{
char chk; int j;
cout<<"\n\nPress any key to continue...";
chk=getch();
j=chk;
for(int i=1;i<=256;i++)
if(i==j) break;
clrscr();
}


void main()
{
clrscr();
check();
cout<<"\n\nIt works!";
getch();
}

It should be noted that getch is not part of the standard library.

If you're using Visual Studio 2012 or older, use the getch() function, if you are using Visual Studio 2013 or newer, use _getch(). You will have to use #include <conio.h>. Example:

#include <iostream>
#include <conio.h>


int main()
{
std::cout << "Press any key to continue. . .\n";
_getch(); //Or getch()
}

If you look up kbhit() function on MSDN now, it says the function is deprecated. Use _kbhit() instead.

#include <conio.h>
int main()
{
_kbhit();
return 0;
}
#include <iostream>
using namespace std;


int main () {
bool boolean;
boolean = true;


if (boolean == true) {


cout << "press any key to continue";
cin >> boolean;


}
return 0;
}

Another option is using threads with function pointers:

#include <iostream>
#include <thread> // this_thread::sleep_for() and thread objects
#include <chrono> // chrono::milliseconds()


bool stopWaitingFlag = false;


void delayms(int millisecondsToSleep)
{
std::this_thread::sleep_for(std::chrono::milliseconds(millisecondsToSleep));
}


void WaitForKey()
{
while (stopWaitingFlag == false)
{
std::cout<<"Display from the thread function"<<std::endl;
delayms(1000);
}
}


 



int main()
{
std::thread threadObj(&WaitForKey);


char userInput = '\0';
while (userInput != 'y')
{
std::cout << "\e[1;31mWaiting for a key, Enter 'y' for yes\e[0m" << std::endl;
std::cin >> userInput;
if (userInput == 'y') {
stopWaitingFlag = true;
}
}
if (threadObj.joinable())
threadObj.join();


std::cout<<"Exit of Main function"<<std::endl;
return 0;
}