Комментарии 14
Как получить событие нажатия на клавишу, я не смог разобраться (если кто знает поделитесь в комментариях).
Я бы начал эксперименты с 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 так ? если да то как ОС понимает откуда когда читать и получаеться что ОС все время читает из этих файлов что бы понять что юзверь нажал на мышку или клаву ?
Прочитал вашу статью и тоже проникся благодарностью по поводу того, что вам было не лень подробно описать возникшие сложности и пути решения.
Вообще странно, что такие, вроде как совершенно обычные действия, как неблокирующее ожидания ввода с клавиатуры, отрисовка пикселя, загрузка текста по http(s) ссылке не имеют простого понятного алгоритма решения. Вот прям не хватает книги -- как простейшим образом реализовать самые востребованные задачи на С++. Может и есть где то такая.
Хочется посоветовать посмотреть на ftxui и возможно использовать эту библиотеку для полной отрисовки ui , а возможно позаимствовать из нее работу с терминалом
Четко и понятно! интересно было прочитать, хоть у меня и область совсем другая
Вообще круто, очень позновательно спасибо
Хочу поделиться с вами своим опытом разработки терминальных приложений и игр. Так как вы уже использовали библиотеку termios, то хороший пример есть тут, для работы с некононичным режимом.
Далее есть ещё библиотека ncurses и вообще я бы посоветовал пользоваться именно ей, чтобы облегчить работу с терминальным курсором или же кареткой, так же в ней есть функции для обработки нажатий с клавиатуры, типа getch. Все утилиты вроде network manager, links, gdb в качестве tui(terminal user interface) под капотом используют curses или наследника ncurses. Подробнее можно почитать тут.
Удачи в изучении и разработке!!!
Лиха беда начала! С фантазией, упорством и головой любые стены рухнут! Рано или поздно
Hidden text
(при условии что у головы бесконечная прочность и жизненная сила)
Успехов в освоении геймдева, терминала, линукса и С/C++!!!)
А можно что-то подкрутить, добавить немного арта и чиптюн музыки - и вперёд на демосцену!
Как написать 2D игру на C++ и чистом STL для терминала в Linux