Pull to refresh

Comments 13

Как получить событие нажатия на клавишу, я не смог разобраться (если кто знает поделитесь в комментариях).

Я бы начал эксперименты с std::cin.readsome()

Не совсем событие, но и не блокирует. Вполне можно использовать в while(true) {}

или создать поток с помощью std::async и ждать нажатия функцией kbhit()

Спасибо за комментарий, да я знаю про kbhit это функция из conio.h которая работает под dos системами (Windows и подобные) в линуксе на котором я разрабатывал игру этого файла по умолчанию нет, есть аналоги типа linux-conioh - реализация conio.h для linux на основе ncurses но как я писал в статье, я хотел обойтись только возможностями STL и не использовать сторонние библиотеки

Спасибо за комментарий, не знаю как я сам не нашел в интернете про std::cin.readsome()

Попробовал использовать, оно действительно работает без блокировки вывода, но только если выключить синхронизацию  буферов Cи и C++ к примеру таким образом

std::ios_base::sync_with_stdio(false);
в документации предупреждают что это может привести к рассинхрону вывода т.е

#include <iostream> 
#include <cstdio>
 
int main ( ) 
{ 
    std :: ios :: sync_with_stdio ( false ) ; 
    std:: cout  <<  "a \n " ; 
    std:: printf ( "b \n " ) ; 
    std:: cout  <<  "c \n " ; 
}

в результате получим

б
а
с

для меня это критично так как рендеринг должен происходить поэтапно иначе получим кашу вместо четко отрисованного кадра, непонятно на сколько это вероятное событие

Добрый день, не совсем понял что вы имеете ввиду ?

Я знаю, что терминал не поддерживает изображения и канвас.

Это не совсем так. Как вам пингвинов в консоли рисуют при старте Linux. https://en.wikipedia.org/wiki/Linux_framebuffer

Можно было попробовать с xdg-open или fim

Нерелевантно. Xdg-open - это просто приложение-прослойка, запускающее просмотрщик файла (выбираемый юзером). Как правило этот просмотрщик не консольный, а графический, например feh или Eye of Gnome. Самостоятельной способности открывать изображение в терминале итд у xdg-open нет. Fim - уже ближе, это приложение для вывода графики в POSIX терминал через пресловутый framebuffer, но вам в любом случае нужно не приложение, а библиотека (API), тк вы пишете свою программу. Но ок, вы ниже говорите что будете выводить только текст и псевдографику.

Как получить событие нажатия на клавишу, я не смог разобраться (если кто знает поделитесь в комментариях)

Если вы пишете код не ядра, а прикладной программы (пространство пользователя), самый низкий уровень работы с клавиатурой, доступный вам, - это /dev/input. Это i/o устройство, предоставляемое ядром линукс и являющееся абстракцией над устройствами ввода. Там отражаются и все нажатия клавиш. Взаимодействовать с ним из кода на Си можно через заголовочный файл ядра линукс, linux/input.h, примерно так:

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <stdio.h>

int main(void)
{
    const char *dev = "/dev/input/event0";
    struct input_event ev;
    ssize_t n;
    int fd;

    fd = open(dev, O_RDONLY);
    if (fd == -1) {
        fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
        return EXIT_FAILURE;
    }

    while (1) {
        n = read(fd, &ev, sizeof ev);
        if (n == (ssize_t)-1) {
            if (errno == EINTR)
                continue;
            else
                break;
        } else
        if (n != sizeof ev) {
            errno = EIO;
            break;
        }

        if (ev.type == EV_KEY)
            printf("%d 0x%04x\n", ev.value, ev.code);
    }

    return 0;
}

Но на настолько низком уровне взаимодействовать с клавиатурой не стоит (если вы только не пишете кейлоггер или ещё какой низкоуровневый специальный софт), по следующим причинам:

  • Право чтения /dev/input напрямую - это весьма неслабая привилегия. Простой юзер в линукс её лишён по соображениям безопасности (программу выше возможно запустить только от рута) тк иначе он сможет считывать с /dev/input ввод других юзеров.

  • В приложении обычно важно знать не физическую нажимаемую клавишу, а её символ (keysym), интерпретируемый из скан-кода клавиши. Например если вы жмёте "я" в русской раскладке, то в /dev/input это то же самое событие, что и нажатие "z".

По приложению - имхо вы зря пишете цикл чтения клавиатурного ввода с нуля.
Упражнение в чём-то полезное, но проще воспользоваться консольным фреймворком. Канонический - ncurses, правда это C а не C++. Он берёт на себя создание event loop, диспетчеризацию событий от клавиатуры, отрисовку итд. Клавиатурный ввод будете читать через Ncurses API.

если кто знает как увеличить шрифт в терминале через C++ напишите в комменты

Странное желание. Консольное приложение не должно хотеть/мочь манипулировать шрифтом. Оно оперирует вводом и выводом текстовых символов на матрице 80x25 (стандарт, у юзера мб другой размер), а как этот текст отображается - это вопрос настроек эмулятора терминала у юзера. Если юзеру покажется, что текст мелковат, пусть увеличивает у себя, это не ваша забота

Спасибо за подробный ответ, круто что есть люди которым не лень поделиться знаниями.

Про ncurses знал и понимал что надо использовать его, но специально не использовал, хотелось грубже копнуть в понимание как устроен ввод-вывод, графика, и прочее. Я же все таки это ради своего обучения и развития делаю.

По поводу /dev/input видил у соера на канале видео где он рассказывает про это, логично что так низко читать события плохо по безопасности, но ради образования я попробовал и не совсем понял почему event0 отвечает за ввод с клавиатуры ? и что все остальные event делают у меня их к примеру 30 штук в /dev/input ? и еще я так понимаю что каждое подключаемое устройство к ПК будет создавать по какому то интерфейсу свой новый event ? например если я подключил одну мышку это mouse0 потом подключил вторую и это уже mouse1 так ? если да то как ОС понимает откуда когда читать и получаеться что ОС все время читает из этих файлов что бы понять что юзверь нажал на мышку или клаву ?

Хочется посоветовать посмотреть на ftxui и возможно использовать эту библиотеку для полной отрисовки ui , а возможно позаимствовать из нее работу с терминалом

Четко и понятно! интересно было прочитать, хоть у меня и область совсем другая

Вообще круто, очень позновательно спасибо

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

Далее есть ещё библиотека ncurses и вообще я бы посоветовал пользоваться именно ей, чтобы облегчить работу с терминальным курсором или же кареткой, так же в ней есть функции для обработки нажатий с клавиатуры, типа getch. Все утилиты вроде network manager, links, gdb в качестве tui(terminal user interface) под капотом используют curses или наследника ncurses. Подробнее можно почитать тут.

Удачи в изучении и разработке!!!

Лиха беда начала! С фантазией, упорством и головой любые стены рухнут! Рано или поздно

Hidden text

(при условии что у головы бесконечная прочность и жизненная сила)

Успехов в освоении геймдева, терминала, линукса и С/C++!!!)

А можно что-то подкрутить, добавить немного арта и чиптюн музыки - и вперёд на демосцену!

Sign up to leave a comment.

Articles