2017-05-07 11 views
4

Win API ReadConsole(...)を使用しようとしていますが、コンソールからの入力を中止するために区切り文字を渡したいとします。 以下のコードは動作しますが、入力は\r\nの読み込みを停止します。 例えば、'.'のコンソール入力の読み上げをやめてください。win api readConsole()

void read(char *cIn, char delim) 
{ 
    HANDLE hFile; 
    DWORD charsRead; 
    DWORD charsToRead = MAX_PATH; 
    CONSOLE_READCONSOLE_CONTROL cReadControl; 

    cReadControl.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL); 
    cReadControl.nInitialChars = 0; 
    cReadControl.dwCtrlWakeupMask = delim; 
    cReadControl.dwControlKeyState = NULL; 

    DWORD lpMode; 



// char cIn[MAX_PATH]; //-- buffer to hold data from the console 

    hFile = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, 
        OPEN_EXISTING, 0, NULL); 

    GetConsoleMode(hFile,&lpMode); 
// lpMode &= ~ENABLE_LINE_INPUT; //-- turns off this flag 
// SetConsoleMode(hFile, lpMode); //-- set the mode with the new flag off 

    bool read = ReadConsole(hFile, cIn, charsToRead * sizeof(TCHAR), &charsRead, &cReadControl); 
    cIn[charsRead - 2] = '\0'; 
} 

私はこれを行うには、他の簡単な方法がある知っているが、私はただ勝利のAPI機能のいくつかを理解しようとするとどのようにそれらを使用することになっています。

ありがとうございます。

+0

フルコントロールコンソールの入力を希望し、押されたときに(* VK_RETURN *を待つのではなく)、* ReadConsoleInput *が必要です。ReadConsole * – RbMm

+0

@RbMmありがとうございます。 – dmaelect

答えて

5

私はこの質問を見て、些細なことだと思っていましたが、最後の30分を理解して最終的に何かを得ようとしました。

そのdwCtrlWakeupMaskは、CONSOLE_READCONSOLE_CONTROLに記載されていません。 MSDNは "読み取りが完了したことを知らせるためにユーザー定義の制御文字が使用されています"と言いますが、なぜそれがmaskと呼ばれていますか? TCHARのようなものではなく、なぜULONGなのですか?私はそれをチャーミングしてみたが、何も起こらなかったので、もっと話があるはずです。

私は、その特定の変数を探してウェブに取り、このリンクが見つかりました:それは助けを求めるコーダランダム囲碁ライブラリで、答えはタブが1 << '\t'であるということです https://groups.google.com/forum/#!topic/golang-codereviews/KSp37ITmcUgを。私はそれを試して、それは動作します!

今後のウェブ検索ユーザーのために、dwCtrlWakeupMaskは、ReadConsoleを返すASCII制御文字のビットマスクです。あなたは|をあなたの好きなように多く1 << ctrl_charsとすることができますが、32ビット値のビットマスクであるため任意の文字にすることはできません。chars1〜31のみが可能です(このグループbtwはcontrolタブ、バックスペース、ベルのようなものが含まれ、印刷可能な文字自体を表すものではありません)。したがって

、このマスク:

cReadControl.dwCtrlWakeupMask = (1 << '\t') | (1 << 0x08); 

タブ(\t)ORバックスペース(0x08)が押されたときReadConsoleを返すことになります。

ctrl+ some_ascii_valueによって表される文字はそう== 1から始まる、英語のアルファベットで、その文字の数です、ctrl+d4あり、そしてctrl+z26です。ユーザーはctrl+dがそう、これは素敵な互換性のものになるかもしれません当たったときのLinux端末ドライバもreadに返すこと

cReadControl.dwCtrlWakeupMask = (1 << 4) | (1 << 26); 

注:ユーザーがctrl+dctrl+zに当たると

したがって、これが返されます。

この引数のポイントは、処理された入力モードでタブ補完が簡単にできるようにすることです。それ以外の場合は、処理された入力をオフにして、キーを1つずつ処理する必要があります。今はあなたが... ... tbhでも、私はまだ対話型プログラムの入力をReadConsoleInputとすることを好んでいます。

しかし、他の多くの方法がありますが、.をデリミタとして使用することは不可能ですが、値> 32なので、自分でやる必要があります。とにかくこれは私には面白いですし、Web上には乏しいリソースがありますので、私はこれを今後の参考のために書いています。

これはwineconsoleで動作するようには見えないので、実際のWindowsボックスに入れてテストしてください。

ここでは、実際にはdwControlKeyStateが関数によって設定されています。渡された値は無視されます(少なくとも私が知る限り)が、関数が返ってくると、指定されたフラグを調べることができます。たとえば、ReadConsoleを呼び出してキーを押すと、numlockがオンの場合は32になります。それはnumlockがオンで、shift + tab(そしてnumlockをオンにした)を押したときに48になります。したがって、関数が返った後にテストします。

私はMSDNドキュメントを好きですが、IMOはこのパラメータを説明する上で完全にボールを落としました!

1

このコードはばかげているでしょう。これを行う唯一の方法は、もっともらしいです。後でReadFileを使用するように適合させる必要がある場合は、それ以上の入力を消費しない唯一の方法です。

ほとんどの場合、標準の入力ハンドルでReadFileを使用したい場合は、ほとんどの場合ReadConsoleは必要ありませんが、私は迂回します。

char *cInptr = cIn; 
do { 
    bool read = ReadConsole(hFile, cInptr, sizeof(TCHAR), &charsRead, &cReadControl); 
    if (read) cInptr += charsRead; 
} while (read && charsRead > 0 && cInptr[-1] && cInptr[-1] != '.'); 

私はループの中で非常に多くのテストをパラノイドにしている可能性があります。私は、ReadConsoleの契約によって暗示されているものを判断するためのすべての述語を調べるつもりはない。

関連する問題