按任意鍵繼續 . . .
這通常是Windows上的一個問題,原因是有些非常糟糕的IDE不知道如何確保程式完成後控制檯保持開啟。然而,這確實觸及了您思考程式設計方式的一個主要哲學問題。畢竟,控制檯程式應該從
控制檯執行——否則一旦它終止,控制檯
就應該消失。我們稍後會解決這個問題。目前,我們先專注於眼前的問題。
- - - - - - - - - - - - - - - - 簡單答案 - - - - - - - - - - - - - - - -
雖然簡單,但這確實是一件
壞事。請參閱
為什麼system()很糟糕瞭解更多。
1 2 3 4 5 6 7
|
#ifdef __cplusplus__
#include <cstdlib>
#else
#include <stdlib.h>
#endif
system("PAUSE");
|
它也僅限於Windows。要在Linux上執行相同操作,您需要使用
read shell命令
1 2
|
system("read -p \"Press a key to continue...\" -n 1 -s");
|
- - - - - - - - - - - - - - - - 標準方法 - - - - - - - - - - - - - - - -
最正確的方法是這樣的
1 2 3 4 5 6 7 8
|
#include <iostream>
#include <limits>
void PressEnterToContinue()
{
std::cout << "Press ENTER to continue... " << flush;
std::cin.ignore( std::numeric_limits <std::streamsize> ::max(), '\n' );
}
|
1 2 3 4 5 6 7 8 9
|
#include <stdio.h>
void PressEnterToContinue()
{
int c;
printf( "Press ENTER to continue... " );
fflush( stdout );
do c = getchar(); while ((c != '\n') && (c != EOF));
}
|
之後,只需在程式末尾呼叫它即可
1 2 3 4 5 6 7 8
|
#include <stdio.h>
int main()
{
puts( "Hello world!" );
PressEnterToContinue();
return 0;
}
|
這種方法的主要問題在於
它僅在輸入正確同步時才有效。如果不同步,您將需要
重新整理標準輸入。有關正確同步的更多資訊,請參閱
讀取使用者輸入時出現的問題。
此外,它要求使用者按下
回車鍵繼續。這可能不像您想的那麼糟糕。神秘的
任意鍵讓很多人感到困惑。(一個更好的說法應該是“按任意鍵繼續……”——最壞的情況下,人們會按下
A鍵。)請記住,
非程式設計師幾乎總是您的目標受眾。即使不是,您想到的內容通常也不像您想象的那麼明顯。請確保向用戶提供關於您的程式接下來需要何種輸入的清晰指示。
A鍵。)請記住,
非程式設計師幾乎總是您的目標受眾。即使不是,您想到的內容通常也不像您想象的那麼明顯。請確保向用戶提供關於您的程式接下來需要何種輸入的清晰指示。
- - - - - - - - - - - - - - - - 使用NCurses - - - - - - - - - - - - - - - -
Curses庫是為處理控制檯而設計的。優點:它是跨平臺的。缺點:它與標準流的互動不太好。換句話說,您不應該混合使用
printf()等或
cout等與curses。二者選一,不要混用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
#include <curses.h>
int main()
{
initscr();
addstr( "Hello world!\n\n" );
addstr( "\nPress a key to continue..." );
cbreak(); /* turn off line-buffering */
noecho(); /* turn off character echo */
getch(); /* read and discard a single character (caveats!) */
echo(); /* turn echo back on */
nocbreak(); /* turn line-buffering back on */
endwin();
return 0;
}
|
在使用[
w]
getch()時,還有一些其他事項需要注意。請務必閱讀
開始使用Curses。
因此,如果您的所有需求只是暫停程式一兩次,那麼使用Curses就有點大材小用了。
- - - - - - - - - - - - - - - - 使用<conio.h> - - - - - - - - - - - - - - - -
首先,是一些程式碼。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
#include <conio.h>
#include <stdio.h>
void PressAKeyToContinue()
{
int c;
printf( "\nPress a key to continue..." );
c = getch();
if (c == 0 || c == 224) getch();
}
int main()
{
puts( "Hello world!" );
PressAKeyToContinue();
return 0;
}
|
該庫已嚴重棄用,但它非常流行,以至於在大多數80x86硬體編譯器上都存在某種形式的它——幾乎總是在Windows編譯器上,並且也存在Linux版本。然而,如果可以的話,請使用
NCurses……
需要注意的是,它是
非標準的,這意味著它提供的實際函式變化很大,而且它們的行為並不總是恰到好處。(微軟很多年前就發明了它。沒錯,
不是Borland——儘管Borland因此[臭名昭著])。
因此,對於Windows程式以外的任何程式,它也是一個次優的解決方案。請參閱
使用<conio.h>瞭解更多。
- - - - - - - - - - - - - - - - 特定於作業系統的實現方式 - - - - - - - - - -
要做得更好,您需要做一些特定於作業系統的操作。C,特別是C++的設計理念之一是,作業系統不存在(或者如果存在,它是一個神奇的黑盒子)。因此,要做一些與控制檯相關的特殊操作(記住,C和C++不知道什麼是控制檯)意味著您將不得不編寫與您的作業系統相關的特殊程式碼。
這是一個真正允許您按任意鍵並返回被按下鍵的函式。Windows提供了一些不錯的、簡單的函式來處理控制檯。在Linux上需要更多的“魔法”,但幾乎和它一樣簡單。
Windows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
/* ---------------------------------------------------------------------------
* PressAnyKey()
* ---------------------------------------------------------------------------
* Copyright 2008 Michael Thomas Greer
* <a href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>
*
* function
* Optionally print a message and and wait for the user to press (and
* release) a single key.
*
* arguments
* The message to print. If NULL, uses a default message. Specify the empty
* string "" to not print anything.
*
* returns
* The virtual keycode for the key that was pressed.
*
* Windows #defines virtual keycode values like
* VK_UP
* VK_DOWN
* VK_RIGHT
* VK_LEFT
* which you can use to identify special keys.
*
* Letter keys are simply the upper-case ASCII value for that letter.
*/
#include <windows.h>
int PressAnyKey( const char *prompt )
{
DWORD mode;
HANDLE hstdin;
INPUT_RECORD inrec;
DWORD count;
char default_prompt[] = "Press a key to continue...";
/* Set the console mode to no-echo, raw input, */
/* and no window or mouse events. */
hstdin = GetStdHandle( STD_INPUT_HANDLE );
if (hstdin == INVALID_HANDLE_VALUE
|| !GetConsoleMode( hstdin, &mode )
|| !SetConsoleMode( hstdin, 0 ))
return 0;
if (!prompt) prompt = default_prompt;
/* Instruct the user */
WriteConsole(
GetStdHandle( STD_OUTPUT_HANDLE ),
prompt,
lstrlen( prompt ),
&count,
NULL
);
FlushConsoleInputBuffer( hstdin );
/* Get a single key RELEASE */
do ReadConsoleInput( hstdin, &inrec, 1, &count );
while ((inrec.EventType != KEY_EVENT) || inrec.Event.KeyEvent.bKeyDown);
/* Restore the original console mode */
SetConsoleMode( hstdin, mode );
return inrec.Event.KeyEvent.wVirtualKeyCode;
}
|
POSIX(Unix、Linux、Mac OSX等)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
/* ---------------------------------------------------------------------------
* PressAnyKey()
* ---------------------------------------------------------------------------
* Copyright 2008 Michael Thomas Greer
* <a href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>
*
* function
* Optionally print a message and and wait for the user to press (and
* release) a single key.
*
* arguments
* The message to print. If NULL, uses a default message. Specify the empty
* string "" to not print anything.
*
* returns
* The keycode for the key that was pressed.
*
* Extended key codes (like arrow keys) are properly handled, but their
* keycode is not understood; they are simply returned as the last code in
* the sequence, negated. For example, it is likely that the arrow keys are:
*
* UP_ARROW = -'A' = -65
* DOWN_ARROW = -'B' = -66
* RIGHT_ARROW = -'C' = -67
* LEFT_ARROW = -'D' = -68
*
* Exactly identifying the values for these keys requires a foray into the
* terminfo database, which is a subject for later. For now we'll leave it
* at this.
*/
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
int PressAnyKey( const char* prompt )
{
#define MAGIC_MAX_CHARS 18
struct termios initial_settings;
struct termios settings;
unsigned char keycodes[ MAGIC_MAX_CHARS ];
int count;
tcgetattr( STDIN_FILENO, &initial_settings );
settings = initial_settings;
/* Set the console mode to no-echo, raw input. */
/* The exact meaning of all this jazz will be discussed later. */
settings.c_cc[ VTIME ] = 1;
settings.c_cc[ VMIN ] = MAGIC_MAX_CHARS;
settings.c_iflag &= ~(IXOFF);
settings.c_lflag &= ~(ECHO | ICANON);
tcsetattr( STDIN_FILENO, TCSANOW, &settings );
printf( "%s", prompt ? prompt : "Press a key to continue..." );
count = read( stdin, (void*)keycodes, MAGIC_MAX_CHARS );
tcsetattr( STDIN_FILENO, TCSANOW, &initial_settings );
return (count == 1)
? keycodes[ 0 ]
: -(int)(keycodes[ count -1 ]);
}
|
如果您正在使用C++,您可以這樣增加一些便利性
1 2 3 4 5 6 7
|
#if defined(__cplusplus)
#include <string>
inline int PressAnyKey( const std::string& prompt = "Press a key to continue..." )
{
return PressAnyKey( prompt.c_str() );
}
#endif
|
好了,就到這裡吧。要了解更多關於無緩衝(也稱為“原始”)輸入的資訊,請看看
讀取單個按鍵作為輸入。
好了,今天就到這裡。