これは私にはめったに起こらないので、私がこれをどのように行ったかは決して覚えていません。しかし、CまたはC++では、改行を待たずに標準入力から文字を読み取る最良の方法は何ですか(Enterキーを押します)。
また、理想的には、入力文字を画面にエコーしません。コンソール画面に影響を与えずにキーストロークをキャプチャしたいだけです。
純粋なC++では、stdin
(通常はラインバッファリング)で接続されている可能性のある端末に大きく依存するため、移植可能な方法では不可能です。ただし、そのためにライブラリを使用できます。
conioはWindowsコンパイラで利用可能です。 Enterキーを待たずに文字を与えるには、_getch()
関数を使用します。私は頻繁にWindows開発者ではありませんが、クラスメートが<conio.h>
を含めて使用するのを見てきました。ウィキペディアの conio.h
を参照してください。 Visual C++で非推奨と宣言されているgetch()
をリストします。
linuxで利用可能なcurses。互換性のあるcurses実装は、Windowsでも利用できます。また、getch()
関数もあります。 (マンページを表示するには、man getch
を試してください)。ウィキペディアの Curses を参照してください。
プラットフォーム間の互換性を目指す場合は、cursesを使用することをお勧めします。そうは言っても、ラインバッファリングをオフにするために使用できる関数があると確信しています(「クックモード」ではなく「ローモード」と呼ばれると思います-man stty
を調べてください)。私が間違っていなければ、呪いはあなたのためにポータブルな方法でそれを処理します。
Linux(および他のUnix系システム)では、これは次の方法で実行できます。
#include <unistd.h>
#include <termios.h>
char getch() {
char buf = 0;
struct termios old = {0};
if (tcgetattr(0, &old) < 0)
perror("tcsetattr()");
old.c_lflag &= ~ICANON;
old.c_lflag &= ~ECHO;
old.c_cc[VMIN] = 1;
old.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSANOW, &old) < 0)
perror("tcsetattr ICANON");
if (read(0, &buf, 1) < 0)
perror ("read()");
old.c_lflag |= ICANON;
old.c_lflag |= ECHO;
if (tcsetattr(0, TCSADRAIN, &old) < 0)
perror ("tcsetattr ~ICANON");
return (buf);
}
基本的に、標準モード(およびエコーを抑制するにはエコーモード)をオフにする必要があります。
同じ問題を解決しようとしているときに、別のフォーラムでこれを見つけました。私が見つけたものから少し変更しました。それは素晴らしい作品です。私はOS Xを実行しているため、Microsoftを実行している場合は、rawモードおよびcookedモードに切り替えるための正しいsystem()コマンドを見つける必要があります。
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
// Output Prompt
cout << "Press any key to continue..." << endl;
// Set terminal to raw mode
system("stty raw");
// Wait for single character
char input = getchar();
// Echo input:
cout << "--" << input << "--";
// Reset terminal to normal "cooked" mode
system("stty cooked");
// And we're out of here
return 0;
}
CONIO.H
必要な機能は次のとおりです。
int getch();
Prototype
int _getch(void);
Description
_getch obtains a character from stdin. Input is unbuffered, and this
routine will return as soon as a character is available without
waiting for a carriage return. The character is not echoed to stdout.
_getch bypasses the normal buffering done by getchar and getc. ungetc
cannot be used with _getch.
Synonym
Function: getch
int kbhit();
Description
Checks if a keyboard key has been pressed but not yet read.
Return Value
Returns a non-zero value if a key was pressed. Otherwise, returns 0.
libconio http://sourceforge.net/projects/libconio
または
Conio.hのLinux c ++実装 http://sourceforge.net/projects/linux-conioh
#include <conio.h>
if (kbhit() != 0) {
cout << getch() << endl;
}
これは、kbhit()
を使用してキーボードが押されているかどうかを確認し、getch()
を使用して押されている文字を取得します。
Windowsを使用している場合は、 PeekConsoleInput を使用して入力があるかどうかを検出できます。
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD events;
INPUT_RECORD buffer;
PeekConsoleInput( handle, &buffer, 1, &events );
次に、ReadConsoleInputを使用して入力文字を「消費」します。
PeekConsoleInput(handle, &buffer, 1, &events);
if(events > 0)
{
ReadConsoleInput(handle, &buffer, 1, &events);
return buffer.Event.KeyEvent.wVirtualKeyCode;
}
else return 0
正直に言うと、これは私が持っている古いコードからのものであるため、少し手を加えなければなりません。
ただし、クールなのは、何も入力せずに入力を読み取るため、文字がまったく表示されないことです。
Windowsを想定して、ReadConsoleInput関数を見てください。
CとC++はI/Oの非常に抽象的な視点を取り、あなたが望むことをする標準的な方法はありません。取得するものがあれば、標準入力ストリームから文字を取得する標準的な方法があり、他の言語ではどちらも定義されていません。したがって、おそらくオペレーティングシステムだけでなく、ソフトウェアフレームワークにも依存する、プラットフォーム固有の回答が必要になります。
ここには合理的な推測がいくつかありますが、ターゲット環境が何であるかを知らずに質問に答える方法はありません。
ポータブルに最も近いのは、 ncurses
ライブラリを使用して端末を「cbreakモード」にすることです。 APIは巨大です。最も必要なルーチンは
initscr
およびendwin
cbreak
およびnocbreak
getch
幸運を!
Kbhit()を使用してcharが存在するかどうかを確認し、getchar()を使用してデータを読み取ります。 Windowsでは、「conio.h」を使用できます。 Linuxでは、独自のkbhit()を実装する必要があります。
以下のコードを参照してください:
// kbhit
#include <stdio.h>
#include <sys/ioctl.h> // For FIONREAD
#include <termios.h>
#include <stdbool.h>
int kbhit(void) {
static bool initflag = false;
static const int STDIN = 0;
if (!initflag) {
// Use termios to turn off line buffering
struct termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initflag = true;
}
int nbbytes;
ioctl(STDIN, FIONREAD, &nbbytes); // 0 is STDIN
return nbbytes;
}
// main
#include <unistd.h>
int main(int argc, char** argv) {
char c;
//setbuf(stdout, NULL); // Optional: No buffering.
//setbuf(stdin, NULL); // Optional: No buffering.
printf("Press key");
while (!kbhit()) {
printf(".");
fflush(stdout);
sleep(1);
}
c = getchar();
printf("\nChar received:%c\n", c);
printf("Done.\n");
return 0;
}
Returnキーを押さずに入力を読み取るループが常に必要でした。これは私のために働いた。
#include<stdio.h>
main()
{
char ch;
system("stty raw");//seting the terminal in raw mode
while(1)
{
ch=getchar();
if(ch=='~'){ //terminate or come out of raw mode on "~" pressed
system("stty cooked");
//while(1);//you may still run the code
exit(0); //or terminate
}
printf("you pressed %c\n ",ch); //write rest code here
}
}
以下はExpert C Programming:Deep Secretsから抽出されたソリューションで、SVr4で動作するはずです。 sttyおよびioctlを使用します。
#include <sys/filio.h>
int kbhit()
{
int i;
ioctl(0, FIONREAD, &i);
return i; /* return a count of chars available to read */
}
main()
{
int i = 0;
intc='';
system("stty raw -echo");
printf("enter 'q' to quit \n");
for (;c!='q';i++) {
if (kbhit()) {
c=getchar();
printf("\n got %c, on iteration %d",c, i);
}
}
system("stty cooked echo");
}
ncursesは、これを行う良い方法を提供します!また、これは私の最初の投稿(覚えている)なので、コメントは大歓迎です。便利なものに感謝しますが、すべて歓迎します!
コンパイルするには:g ++ -std = c ++ 11 -pthread -lncurses .cpp -o
#include <iostream>
#include <ncurses.h>
#include <future>
char get_keyboard_input();
int main(int argc, char *argv[])
{
initscr();
raw();
noecho();
keypad(stdscr,true);
auto f = std::async(std::launch::async, get_keyboard_input);
while (f.wait_for(std::chrono::milliseconds(20)) != std::future_status::ready)
{
// do some work
}
endwin();
std::cout << "returned: " << f.get() << std::endl;
return 0;
}
char get_keyboard_input()
{
char input = '0';
while(input != 'q')
{
input = getch();
}
return input;
}
windows上で私のために働く:
#include <conio.h>
char c = _getch();
SDL(Simple DirectMedia Library)を使用して移植可能にできますが、その動作が気に入らないかもしれません。試したとき、SDLに新しいビデオウィンドウを作成して(プログラムには必要ありませんでした)、このウィンドウにほぼすべてのキーボードとマウスの入力を「グラブ」させる必要がありました(使用には問題ありませんが、他の状況では迷惑または実行不能になります)。完全な移植性が必須である場合を除いて、やり過ぎであり、価値がないと思われます。
ところで、もしあなたがそれに興味があるなら、これはキープレスとリリースイベントを別々に与えます。