LINUX.ORG.RU

getchar() или getch()? вполне могу ошибаться - С не помню ни фига

nnm
()

man termios

anonymous
()

uses
Crt;

Readkey()

Use FreePascal, Luke!

anonymous
()
Ответ на: комментарий от anonymous

Его нет в стандарте и он не перенесён на все платформы.

Legioner ★★★★★
()
Ответ на: комментарий от sergey_feo

> http://www.linux.org.ru/view-message.jsp?msgid=2891939 / Нумбер
> два, > смотрим код...
> Работает :-)

Эх, работает, да не так...
При нажатии q в латинской раскладке срабатывает 1 раз, в русской
раскладке 2 раза, а клавиши F* - 3 раза. Получается, что считываем не
код нажатой клавиши, а набор байтов для введённого символа, который
(символ) может быть многобайтным...
Неужели система так крута и универсальна, что не позволяет делать
тривиальные вещи?!

sergey_feo
() автор топика
Ответ на: комментарий от sergey_feo

> Это поможет избежать проблемы локалей, многобайтных символов, раскладок?

"press any key to continue" == "any input"

Зачем тебе точно знать, какую клавишу нажали, какой символ ввели? Задача - любой "input" без "жмакания" <enter>

anonymous
()
Ответ на: комментарий от anonymous

> Зачем тебе точно знать, какую клавишу нажали, какой символ ввели? Задача - любой "input" без "жмакания" <enter>

Дело в том, что мы не знаем сколько байт будет этот "any input". В досе мы предполагали что нажатие любой клавиши приводит к помещению в буфер ввода ровно одного байта. Если же мы вернёмся в современный мир, мы увидим разные стрелки/Fx кнопки, которые генерят escape-последовательность из трёх байт. Если используется локаль UTF8, то даже алфавитные клавиши при включённой национальной раскладке будут генерить несколько байт (от 2 в русской раскладке и до хз сколько в других -- например в китайской).

Подытожив: мы просто не знаем, когда any input заканчивается.

anonymous
()

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>

int set_raw_mode(void)
{
    int fd = STDIN_FILENO;
    struct termios t;

    if(tcgetattr(fd, &t) < 0)
    {
        perror("tcgetattr");
        return -1;
    }

    t.c_lflag &= ~(ICANON | ECHO);

    if(tcsetattr(fd, TCSANOW, &t) < 0)
    {
        perror("tcsetattr");
        return -1;
    }

    return 0;
}

int main(int argc, char **argv)
{
    if(set_raw_mode() < 0)
    {
        fprintf(stderr, "Cannot set raw mode\n");
        exit(1);
    }

    getchar();

    printf("Do something here...\n");

    return 0;
}

/* Не забываем вернуть режим назад при выходе */

alex_custov ★★★★★
()
Ответ на: комментарий от anonymous

>>Подытожив: мы просто не знаем, когда any input заканчивается.

в контексте поставленной задачи - когда он заканчивается совершенно не важно. Важно знать, когда он начинается.

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

Теперь запишем исходник так:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <termios.h>

int set_raw_mode(void) { int fd = STDIN_FILENO; struct termios t;

if(tcgetattr(fd, &t) < 0) { perror("tcgetattr"); return -1; }

t.c_lflag &= ~(ICANON | ECHO);

if(tcsetattr(fd, TCSANOW, &t) < 0) { perror("tcsetattr"); return -1; }

return 0; }

int main(int argc, char **argv) { if(set_raw_mode() < 0) { fprintf(stderr, "Cannot set raw mode\n"); exit(1); }

printf("%d", getchar());

printf("Do something here...\n");

printf("%d", getchar());

return 0; }

И попробуем запустить. Первый раз введём например букву W. Тогда после вывода надписи "Do something here...\n" нужно будет ввести ещё что-то.

Теперь запустим ещё раз и введём например Ф. Мы введём сразу два байта. Теперь вопрос: если бы мы ввели Ф, а считали бы только один байт? Правильно, в буфере ввода остался бы мусор!

anonymous
()
Ответ на: комментарий от alex_custov

Теперь запишем исходник так:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>

int set_raw_mode(void)
{
    int fd = STDIN_FILENO;
    struct termios t;

    if(tcgetattr(fd, &t) < 0)
    {
        perror("tcgetattr");
        return -1;
    }

    t.c_lflag &= ~(ICANON | ECHO);

    if(tcsetattr(fd, TCSANOW, &t) < 0)
    {
        perror("tcsetattr");
        return -1;
    }

    return 0;
}

int main(int argc, char **argv)
{
    if(set_raw_mode() < 0)
    {
        fprintf(stderr, "Cannot set raw mode\n");
        exit(1);
    }

    printf("%d", getchar());

    printf("Do something here...\n");

    printf("%d", getchar());

    return 0;
}

И попробуем запустить.  Первый раз введём например букву W.
Тогда после вывода надписи "Do something here...\n" нужно будет
ввести ещё что-то.

Теперь запустим ещё раз и введём например Ф, при условии что локаль UTF8.  Мы введём сразу два байта.  Теперь вопрос: если бы мы ввели Ф,
а считали бы только один байт?  Правильно, в буфере ввода остался
бы мусор!

anonymous
()
Ответ на: комментарий от anonymous

> Use FreePascal, Luke!
Что-то он не рассчитан на configure && make && make install.
Может быть, попробую, когда будет время разобраться с его нестандартной установкой.

> Может while getc(*stdin)==EOF

Лучше while getc(stdin) != EOF, но оно всё равно не работает. Не
возвращает getc EOF при нажатии любой клавиши.

> ...int set_raw_mode(void)...

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

sergey_feo
() автор топика
Ответ на: комментарий от alex_custov

В лучший способ -- сменить сообщение на "press Enter to continue"

anonymous
()

Если не важно получить не сам символ, а просто факт нажатия, то можно делать неблокирующее чтение, которое почти гаратнировано прочитает байты, относящиеся к одному нажатию (конечно же, при умелом оперировании этим самым чтением).

ShprotX
()
Ответ на: комментарий от sergey_feo

> Не возвращает getc EOF при нажатии любой клавиши.

Правильно. Он возвращает EOF пока никакая клавиша не нажималась.

anonymous
()
Ответ на: комментарий от ShprotX

> которое почти гаратнировано прочитает байты, относящиеся к одному нажатию

А потом программу скомпилируют со странной реализацией libc или ещё что-то в таком духе.

anonymous
()
Ответ на: комментарий от anonymous

> А потом программу скомпилируют со странной реализацией libc или ещё что-то в таком духе

Хз, только getch делает то же самое.

ShprotX
()
Ответ на: комментарий от alex_custov

> man fpurge

Да, пример с set_raw_mode() + fpurge = работает!

В смысле вот полностью:

#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>

int set_raw_mode(void)
{
    int fd = STDIN_FILENO;
    struct termios t;

    if(tcgetattr(fd, &t) < 0)
    {
        perror("tcgetattr");
        return -1;
    }

    t.c_lflag &= ~(ICANON | ECHO);

    if(tcsetattr(fd, TCSANOW, &t) < 0)
    {
        perror("tcsetattr");
        return -1;
    }

    return 0;
}

int main(int argc, char **argv)
{
    int i;

    if(set_raw_mode() < 0)
    {
        fprintf(stderr, "Cannot set raw mode\n");
        exit(1);
    }

    for (i=0; ; i++)
    {
        printf("starting № %i\n", i);
        getchar();
        __fpurge(stdin);
    }

    /* Не забываем вернуть режим назад при выходе */

    return 0;
}

После этого примера терминал восстанавливать командой reset :-)

sergey_feo
() автор топика
Ответ на: комментарий от anonymous

>> Не возвращает getc EOF при нажатии любой клавиши.
> Правильно. Он возвращает EOF пока никакая клавиша не нажималась.

Ой :-) А если постоянно делать проверку на EOF - мы не загрузим
процессор на 100%?

sergey_feo
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.