Как я могу сгенерировать BACKSPACE в консоли отладки Visual Studio?

Я пишу программу C в режиме консоли Windows, используя сообщество Visual Studio 2019. Я хочу, чтобы каждый пробел, видимый во входном потоке, печатался как литеральная строка "\b" в выходных данных.

Как вы перехватываете сигнал возврата на консоль? Если я нажму CTRL-H, он удалит предыдущий символ, но на самом деле я должен получить char(), чтобы получить соответствующее значение.

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

person Edmund    schedule 11.04.2020    source источник
comment
Совершенно непонятно, что вы спрашиваете, '\ b' - это символ обратного пробела - что заменить? Ctrl-H — это стандартная последовательность ASCII CTRL для возврата, она работает в Windows cmd и powershell, но также работает и с возвратом. Я понятия не имею, к чему относится консоль отладки Visual Studio. Вы на самом деле используете VS Code, а не VS?   -  person Clifford    schedule 11.04.2020
comment
Это 8 и в консоли Windows cmd тоже. printf("Hello%cu", 8); выводит Hellu.   -  person Weather Vane    schedule 11.04.2020
comment
@Clifford, надеюсь, я сделал полезные разъяснения.   -  person Edmund    schedule 11.04.2020


Ответы (2)


Консоль Windows выполняет редактирование строки на стандартном вводе, позволяя использовать возврат, удаление, курсор влево/вправо и режим вставки/перезаписи. Эти символы и нажатия клавиш не приводят к вставке символа во входной поток.

Вы можете отключить обработку ввода с помощью Win API SetConsoleMode(). Например, ниже я переключил режим обработки и линейного ввода, чтобы getchar() возвращался после ввода каждого символа:

#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 до тех пор, пока не будет введен следующий символ. Без сомнения, для этого есть решение, но я оставлю его вам для экспериментов. Это может быть конфликт между обработкой stdin и обработкой консоли Windows - и, возможно, использование ReadConsole() и функций ввода-вывода консоли Win API в целом поможет?

person Clifford    schedule 12.04.2020
comment
Спасибо за направление, помогло. Мне интересно, если бы я столкнулся с подобной задачей в * nix, как бы я мог к ней подойти. Существует ли нестандартный заголовок C или библиотека для обхода оболочки * nix и обработки редактирования строки? Возможно, GNU Readline является таким ресурсом. Проблема, над которой я работал, - это упражнение из языка программирования C (2-е издание). Я предполагаю, что разработчики упражнения работали с видеотерминалом, поэтому могли просто использовать стандартный (ANSI) C. - person Edmund; 13.04.2020
comment
@ Эдмунд Возможно, это тема для нового вопроса. SO — это не дискуссионный форум, избегайте задавать вопросы в комментариях. - person Clifford; 13.04.2020

У меня есть рабочее решение, использующее 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;
}
person Edmund    schedule 13.04.2020