В BearLibTerminal ввод обрабатывается с помощью функций read, peek, read str, has input, state и check.
Эта функция возвращает следующее событие из очереди ввода:
int key = terminal_read(); if (key == TK_ESCAPE) { // Quit }
Если в очередь ввода пуста, вызов заблокирует выполнение до поступления нового события. Если такое блокируещее поведение нежелательно, можно проверить has input перед вызовом read.
Эта функция аналогична read, но не убирает прочитанное событие из внутренней очереди (следующий вызов peek или read вернет то же значение). Кроме того, вызов этой функции является неблокирующим: если очередь ввода пуста, функция вернет 0.
Эта функция выполняет простое блокирующее чтение строки без какого-либо разбора введенного значения. В процессе выполнения вызова, пользовательский ввод отображается по указанным координатам и ограничивается по размеру и может быть легко вписан в интерфейс игры. Функция отображает ввод в текущем выбранном слое и полностью восстанавливает исходное состояние сцены перед выходом, оставляя сохранение введенной строки на экране на усмотрение приложения.
Функция возвращает размер строки, введенной пользователем и подтвержденной нажатием на Enter, или константу TK_INPUT_CANCELLED, если ввод был отменен нажатием на Escape или вовсе попыткой закрытия окна.
wchar_t s[32] = L"Hello"; if (terminal_read_wstr(2, 1, s, sizeof(s)-1) >= 0) { terminal_wprintf(L"You entered: \"%ls\"", s); }
Если поведение read_str не удовлетворяет требованиям конкретного приложения, можно использовать состояния ввода TK CHAR/TK WCHAR, позволяющие реализовать произвольный ввод строки.
Эта функция возвращает булево значение, сигнализирующее наличие доступных событий ввода в очереди. Возврат true функцией has_input гарантирует, что следующий вызов read вернет результат сразу же, не блокируя выполнение программы.
while (terminal_has_input()) { int key = terminal_read(); }
Эта функция возвращает текущее численное значение некоторого свойства/состояния библиотеки. При обработке ввода с помощью state запрашиваются различные своства событий ввода, см. таблицу ниже.
int key = terminal_read(); if (key == TK_MOUSE_MOVE) { int x = terminal_state(TK_MOUSE_X); int y = terminal_state(TK_MOUSE_Y); }
Следует отметить, что state, в общем виде, возвращет значение свойства не на момент вызова, а на момент, когда случилось последнее выбранное из очереди событие ввода, см. очередь ввода.
Эта функция является простой оберткой над state. Во многих языках программирования нельзя сравнивать числовые и булевы значения, из-за чего проверка логически булевых состояний посредством постоянного приведения численного результата state к булевому типу может быстро надоесть. Вместо этого можно использовать check для проверки свойств:
int key = terminal_read(); if (key == TK_Z) { if (terminal_check(TK_SHIFT)) { // 'Z': использовать жезл } else { // 'z': прочитать заклинание } }
Опции ввода устанавливаются с помощью функции set:
terminal_set ( "input:" "cursor-symbol = 0x1F," "cursor-blink-rate = 500," "precise-mouse = false," "mouse-cursor = true," "filter=[keyboard];" );
Символ/тайл, используемый в качестве курсора функцией read str. По умолчанию это “_” (символ подчеркивания) и может быть сменен, чтобы соответствовать интерфейсу приложения, например на сплошной прямоугольник или вертикальную черту.
Скорость, с которой мерцает курсор в функции read str, в миллисекундах. По умолчанию 500, т. е. дважды в секунду.
Булев флаг, контролирующий генерацию событий о движении курсора мыши. Если он false, событие генерируется только если курсор перемещается с одного знакоместа на другое. Если флаг true, любое перемещение курсора мыши генерирует событие. По умолчанию параметр выставлен в false.
Булев флаг, контролирующий видимость курсора мыши. По умолчанию true.
Булев флаг, контролирующий реакцию терминала на событие TK_CLOSE. Если он true, единожды сгенерированное событие TK_CLOSE не может быть сброшено, а все последующие вызовы read будут возвращать TK_CLOSE. Обычно это несколько упрощает логику приложения. Когда параметр выставлен в false, событие TK_CLOSE имеет смысл запроса и приложение может его проигнорировать, например спросив подтверждение у пользователя. По умолчанию параметр выставлен в true.
Список событий, в которых заинтересовано приложение, все остальные события будут обработаны библиотекой автоматически и не будут прочитаны приложением. Иными словами, read будет возвращать события только из этого списка. Список задается в виде имен событий, перечисленных через запятую внутри квадратных скобок:
input.filter = [keyboard, mouse+]
Именем события может быть:
Указание имени события или группы событий “включает” их чтение посредством функции read. Если к имени добавлен знак ”+”, то будут докладываться как нажатия клавиши, так и отпускания.
Фильтр по умолчанию – 'keyboard'. Для того, чтобы задействовать мышь, нужно установить фильтр в 'keyboard, mouse'. “Системные” события TK_CLOSE и TK_RESIZED задействованы всегда.
Если список пуст, фильтрация не производится. Для того, чтобы выключить фильтрацию, достаточно установить пустой список в качестве значения input.filter.
Группа | Константа | Описание | |
---|---|---|---|
Буквенно-цифровые | TK_A … TK_Z | Событие: сигнализирует о том, что соответствующая клавиша была нажата или отпущена. Если клавиша была отпущена, то ее коду будет добавлена констатна TK_KEY_RELEASED (еще...). Свойство: текущее состояние клавиши (см. очередь ввода). |
|
TK_0 … TK_9 | |||
TK_SPACE | |||
TK_MINUS | - |
||
TK_EQUALS | = |
||
TK_LBRACKET | [ |
||
TK_RBRACKET | ] |
||
TK_BACKSLASH | \ |
||
TK_SEMICOLON | ; |
||
TK_APOSTROPHE | ' |
||
TK_GRAVE | ` |
||
TK_COMMA | , |
||
TK_PERIOD | . |
||
TK_SLASH | / |
||
Функциональные, навигационные, регистровые | TK_F1 … TK_F12 | ||
TK_RETURN | |||
TK_ESCAPE | |||
TK_BACKSPACE | |||
TK_TAB | |||
TK_PAUSE | |||
TK_INSERT | |||
TK_HOME | |||
TK_PAGEUP | |||
TK_DELETE | |||
TK_END | |||
TK_PAGEDOWN | |||
TK_RIGHT | |||
TK_LEFT | |||
TK_DOWN | |||
TK_UP | |||
TK_SHIFT | |||
TK_CONTROL | |||
Нумпад | TK_KP_0 … TK_KP_9 | ||
TK_KP_DIVIDE | / |
||
TK_KP_MULTIPLY | * |
||
TK_KP_MINUS | - |
||
TK_KP_PLUS | + |
||
TK_KP_PERIOD | . |
||
TK_KP_ENTER | |||
Мышь | TK_MOUSE_LEFT | ||
TK_MOUSE_RIGHT | |||
TK_MOUSE_MIDDLE | |||
TK_MOUSE_X1 | |||
TK_MOUSE_X2 | |||
TK_MOUSE_MOVE | Событие: генерируется, когда курсор мыши перемещается с одного знакоместа на другое (иными словами, с точностью “до знакоместа”). Если включена опция input.precise-mouse, событие генерируется при любом движении курсора мыши. | ||
TK_MOUSE_SCROLL | Событие: генерируется при повороте колесика мыши. | ||
TK_MOUSE_WHEEL | Свойство: возвращает дельту поворота колесика мыши последнего события TK_MOUSE_SCROLL (еще...). | ||
TK_MOUSE_X | Свойство: положение курсора мыши, в знакоместах. | ||
TK_MOUSE_Y | |||
TK_MOUSE_PIXEL_X | Свойство: положение курсора мыши, в пикселях. Эти свойства доступны вне зависимости от опции input.precise-mouse. | ||
TK_MOUSE_PIXEL_Y | |||
TK_MOUSE_CLICKS | Свойство: количество быстрых последовательных щелчков на момент последнего события нажатия кнопки мыши, например 1 для обычного щелчка, 2 для двойного и т. д. (еще...) | ||
Другие свойства | TK_WIDTH | Свойство: размер терминала в знакоместах. | |
TK_HEIGHT | |||
TK_CELL_WIDTH | Свойство: размер знакоместа в пикселях. | ||
TK_CELL_HEIGHT | |||
TK_COLOR | Свойство: текущий цвет переднего плана. | ||
TK_BKCOLOR | Свойство: текущий цвет фона. | ||
TK_LAYER | Свойство: текущий номер слоя. | ||
TK_COMPOSITION | Свойство: текущий флаг композиции. | ||
TK_CHAR | Свойство: Unicode или ANSI код символа, ассоциированного с последним прочитанным событием ввода (еще...). | ||
TK_WCHAR | |||
TK_EVENT | Свойство: код последнего прочитанного события ввода. | ||
TK_FULLSCREEN | Свойство: флаг активности полноэкранного режима. | ||
Другие события | TK_CLOSE | Событие: запрос на закрытие терминала, генерируемый когда пользователь пытается закрыть окно, например щелкнув по кнопке закрытия или нажав Alt+F4 (см. опцию input.sticky-close). | |
TK_RESIZED | Событие: размер окна был изменен пользователем (см. опцию window.resizeable). |
Все генерируемые события ввода попадают во внутреннюю очередь. Чтение этой очереди производится с помощью функции read, причем до тех пор, пока событие не будет выбрано из очереди, оно не окажет никакого воздействия на приведенные выше свойства. У такого механизма есть весьма важное последствие: все связанные со вводом свойства всегда находятся в согласованном состоянии.
Например, пусть пользователь нажал A, а затем Shift+B. Будут сгенерированы следующие события: A⇩ A⇧ Shift⇩ B⇩ Shift⇧ B⇧. Когда приложение в процессе чтения очереди ввода наткнется на некоторое событие нажатия клавиши, можно будет проверить была ли нажата одна клавиша или целая комбинация простым вызовом функции check:
if (key == TK_A && terminal_check(TK_SHIFT)) { // Do something }
Для события A⇩ это условие будет ложным. Для B⇩ ситуация отличается тем, что к тому моменту событие Shift⇩ уже будет выбрано и применено и check вернет true.
Во многих библиотеках проблема проверки нажатия комбинации клавиш решается введением целой структуры события с кодом нажатой клавиши и набором флагов состояния клавиш Shift, Ctrl, клавиш мыши и т. д. BearLibTerminal подходит к этой проблеме несколько по-иному: все связанные со вводом свойства ведут себя как одна большая структура, описывающая произошедшее событие ввода:
if (key == TK_F && terminal_check(TK_SHIFT)) { // Shift+F: поиск, а не выстрел. } else if (key == TK_MOUSE_LEFT && terminal_check(TK_CONTROL)) { // Ctrl+LMB: команда, а не выбор } else if (terminal_state(TK_CHAR) == '?' && terminal_state(TK_MOUSE_Y) < 20) { // Нажатие '?' в то время как курсор мыши находится выше 20-й строки: что бы это ни было }
Следует отметить, что ряд свойств терминала не зависят от очереди и всегда возвращают актуальное состояние, потому что иначе они имели бы мало смысла. Этими свойствами являются: TK_WIDTH, TK_HEIGHT, TK_CELL_WIDTH, TK_CELL_HEIGHT, TK_COLOR, TK_BKCOLOR, TK_LAYER, TK_COMPOSITION, TK_FULLSCREEN.
Эта константа используется для различения нажатия и отпуска клавиши. Для события нажатия клавиши или автоповтора, функци read вернет просто соответствующий код клавиши, например TK_A или TK_BACKSPACE. Для отпущенной же клавиши будет сгенерировано событие с кодом, составленным из кода клавиши и констатнты TK_KEY_RELEASED. Это позволяет легко фильровать события ввода, так как события нажатия и отпуска клавиши имеют различные коды, но при этим могут быть легко сопоставлены:
int key = terminal_read(); if (key == TK_A) { // Нажато 'A' foo(); } else if (key == TK_B|TK_KEY_RELEASED) { // Отпущена 'B' bar(); } else if ((key & ~TK_KEY_RELEASED) == TK_C) { // Клавиша 'C' либо нажата, либо отпущена baz(); }
Автоповтор зажатой клавиши генерирует только события нажатия, без промежуточных события отпуска клавиши. Таким образом, одному событию отпуска клавиши может соотвествовать несколько событий нажатия.
Эти свойства предоставляют способ организации собственного ввода текста. Они возвращают код символа, ассоциированного с последним прочитанным событием ввода. TK_WCHAR возвращает код символа в Unicode, тогда как TK_CHAR – код ANSI, транслированный в соответствии с опцией terminal.encoding.
std::wstring my_read_str(int x, int y, int max) { std::wstring s; while (true) { int key = terminal_read(); if (key == TK_RETURN || key == TK_ESCAPE || key == TK_CLOSE) { // Не делаем различия между подтвеждением и отменой ввода break; } else if (key == TK_BACKSPACE && s.length() > 0) { // Удаляем один символ с конца s.resize(s.length()-1); } else if (terminal_check(TK_WCHAR) && s.length() < max) { // Добавляем символ в конец s += (wchar_t)terminal_state(TK_WCHAR); } // Визуализация ввода terminal_wprintf(x, y, L"%-*ls_", max, s.c_str()); } return s; }
Это свойство возвращает направление и дельту поворота колесика мыши последнего события TK_MOUSE_SCROLL, например 1 или -2:
int key = terminal_read(); if (key == TK_MOUSE_SCROLL) { int amount = terminal_state(TK_MOUSE_WHEEL); if (mouseOverFoo) { fooValue += amount; } else if (mouseOverBar) { barValue += amount; } }
Это свойство возвращает количество быстрых последовательных щелчков кнопкой мыши для последнего события нажатия клавиши мыши:
int key = terminal_read(); if (key == TK_MOUSE_LEFT) { int clicks = terminal_state(TK_MOUSE_CLICKS); if (clicks == 1) { // Выбрать объект под курсором мыши } else if (clicks == 2) { // Выполнить какое-либо действие с выделенным объектом. } }