如何在 visual studio 调试控制台中生成 BACKSPACE?

How can I generate an BACKSPACE in a visual studio debug console?

我正在使用 Visual Studio 2019 社区编写 Windows 控制台模式 C 程序。我希望在输入流中看到的每个退格键在输出中打印为 literal 字符串 "\b"

如何将退格信号捕获到控制台?如果我按 CTRL-H 它会删除前面的字符,但实际上我要 getchar() 获取相应的值。

while ((c = getchar()) != EOF) {
    if (c == '\t') {
        printf("\t");
    }
    else if (c == '\b')
        printf("\b");
    else if (c == '\') {
        printf("\\");
    }
    else
        putchar(c);

Windows 控制台对标准输入执行行编辑处理,允许您使用退格、删除、left/right 光标和 insert/overwrite 模式。这些字符和按键不会导致将字符插入输入流。

您可以使用 Win API SetConsoleMode() 关闭输入处理。例如下面我切换了处理和行输入模式,以便在输入每个字符后 getchar() returns:

#include <stdio.h>   
#include <windows.h>

int main()
{
    HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE); 
    DWORD console_mode = 0 ;
    if( GetConsoleMode( stdin_handle, &console_mode) )
    { 
        console_mode = console_mode & ~(ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) ;
        SetConsoleMode( stdin_handle, console_mode ) ;
    }

    int c = 0 ;
    while( (c = getchar()) != EOF )
    {     
        switch( c )
        {
            case '\t' : printf( "\t" ); break ;
            case '\b' : printf( "\b" ); break ;
            case '\' : printf( "\\" ); break ;
            case '\r' : putchar( '\n' ); break ; // Translate ENTER into Newline
            default : putchar( c ); break ;
        }
    }
}

但是它可能有一些不良的副作用,例如导致 ENTER 被解释为 \r 并且 getchar() 在按下 ENTER 直到下一个字符被输入之后才被解释为 return输入。毫无疑问,有一个解决方案,但我会把它留给你去试验。这可能是标准输入处理和 Windows 控制台处理之间的冲突 - 也许使用 ReadConsole() 和 Win API 控制台 I/O 函数通常会有帮助?

我有一个使用 Win API 和 ReadConsole 的有效解决方案。

#include <Windows.h>
#include <stdlib.h> 
#include <stdio.h>

BOOL readInput(HANDLE hConsoleInput, TCHAR chBuffer, DWORD nNumberOfCharsToRead);

int main(void)
{
    DWORD console_mode = 0;
    HANDLE stdin_handle;
    TCHAR chBuffer = 0;

    stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
    if (GetConsoleMode(stdin_handle, &console_mode))
    {
        console_mode = console_mode & ~(ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT);
        SetConsoleMode(stdin_handle, console_mode);
    }

    if (stdin_handle == INVALID_HANDLE_VALUE) {
        printf("Error getting the handle to the console.\n");
        exit(EXIT_FAILURE);
    }

    while (readInput(stdin_handle, chBuffer, 1)) {
        ;
    }

    CloseHandle(stdin_handle);

    return 0;
}

BOOL readInput(HANDLE hConsoleInput, TCHAR chBuffer, DWORD nNumberOfCharsToRead)
{
    DWORD dwCount;
    BOOL bSuccess;

    bSuccess = ReadConsole(hConsoleInput, &chBuffer, nNumberOfCharsToRead, &dwCount, NULL);

    if (!bSuccess) {
        printf("Error reading from the console.\n");
        exit(EXIT_FAILURE);
    }

    switch (chBuffer)
    {
        case '\t':
            printf("\t");
            break;
        case '\b':
            printf("\b");
            break;
        case '\':
            printf("\\");
            break;
        case '\r':
            putchar('\n');
            break;
        case '\x1a':                //EOF
            return FALSE;
        default:
            putchar(chBuffer);
            break;
        }

    return TRUE;
}