Обновлен модуль сессии. Добавлено чтение нажатия клавиш. Безопасная инициализация сессии. Новые параметры: keypad и escDelay. Обновлены функции проверки вызовов ncurses-функций.
This commit is contained in:
parent
a5778d0de5
commit
057b62b58e
1 changed files with 93 additions and 16 deletions
|
|
@ -1,12 +1,33 @@
|
||||||
module ncui.core.session;
|
module ncui.core.session;
|
||||||
|
|
||||||
import core.stdc.locale : setlocale, LC_ALL;
|
import core.stdc.locale : setlocale, LC_ALL;
|
||||||
import std.exception : enforce;
|
|
||||||
|
|
||||||
import deimos.ncurses;
|
import deimos.ncurses;
|
||||||
|
|
||||||
import ncui.core.ncwin;
|
import ncui.core.ncwin;
|
||||||
import ncui.lib.common;
|
import ncui.lib.checks;
|
||||||
|
import ncui.core.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Глобальный флаг инициализации ncurses для всего процесса.
|
||||||
|
*
|
||||||
|
* Хранит "истину" о том, выполнялась ли успешная инициализация (`initscr()`).
|
||||||
|
* Используется для защиты от повторной инициализации и для быстрых проверок
|
||||||
|
* перед вызовами функций, требующих активной ncurses-сессии.
|
||||||
|
*/
|
||||||
|
private __gshared bool gInitialized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, была ли ncurses-сессия уже инициализирована в текущем процессе.
|
||||||
|
*
|
||||||
|
* Возвращает:
|
||||||
|
* `true`, если ранее была выполнена успешная инициализация (и был поднят `gInitialized`),
|
||||||
|
* иначе `false`.
|
||||||
|
*/
|
||||||
|
bool cursesInitialized() @nogc nothrow
|
||||||
|
{
|
||||||
|
return gInitialized;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Уровень видимости/типа курсора.
|
* Уровень видимости/типа курсора.
|
||||||
|
|
@ -28,7 +49,7 @@ enum Cursor : int
|
||||||
/**
|
/**
|
||||||
* Режим обработки ввода терминалом.
|
* Режим обработки ввода терминалом.
|
||||||
*
|
*
|
||||||
* - `common` — канонический (построчный) режим — ввод приходит после Enter.
|
* - `cooked` — канонический (построчный) режим — ввод приходит после Enter.
|
||||||
* - `cbreak` — посимвольный режим — символы доступны сразу, но часть спец-клавиш/
|
* - `cbreak` — посимвольный режим — символы доступны сразу, но часть спец-клавиш/
|
||||||
* управляющих символов всё ещё может обрабатываться терминалом (сигналы).
|
* управляющих символов всё ещё может обрабатываться терминалом (сигналы).
|
||||||
* - `raw` — "сырой" посимвольный режим — минимальная обработка терминалом,
|
* - `raw` — "сырой" посимвольный режим — минимальная обработка терминалом,
|
||||||
|
|
@ -41,7 +62,7 @@ enum InputMode
|
||||||
/// Сырой посимвольный ввод с минимальной обработкой терминалом.
|
/// Сырой посимвольный ввод с минимальной обработкой терминалом.
|
||||||
raw,
|
raw,
|
||||||
/// Канонический построчный ввод (поведение "как в обычной консоли").
|
/// Канонический построчный ввод (поведение "как в обычной консоли").
|
||||||
common
|
cooked
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -59,13 +80,34 @@ enum Echo
|
||||||
off
|
off
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Режим обработки специальных клавиш в ncurses (`keypad`).
|
||||||
|
*
|
||||||
|
* Когда режим включён, ncurses преобразует специальные клавиши (стрелки, Home/End,
|
||||||
|
* PgUp/PgDn, F1..F12 и т.п.) в коды `KEY_*`, которые удобно обрабатывать в программе.
|
||||||
|
* Когда выключён — многие такие клавиши приходят как последовательности символов
|
||||||
|
* (escape-последовательности), и их приходится разбирать вручную.
|
||||||
|
*/
|
||||||
|
enum Keypad : bool
|
||||||
|
{
|
||||||
|
/// Включить обработку специальных клавиш (`KEY_*`).
|
||||||
|
on = true,
|
||||||
|
/// Выключить обработку специальных клавиш.
|
||||||
|
off = false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Конфигурация терминальной сессии.
|
* Конфигурация терминальной сессии.
|
||||||
*
|
*
|
||||||
* Поля:
|
* Поля:
|
||||||
* - `mode` — режим ввода.
|
* - `mode` — режим ввода.
|
||||||
* - `cursor` — видимость/тип курсора.
|
* - `cursor` — видимость/тип курсора.
|
||||||
* - `echo` — отображать ли вводимые символы.
|
* - `echo` — отображать ли вводимые символы.
|
||||||
|
* - `keypad` — включение обработки специальных клавиш (стрелки, F-клавиши → `KEY_*`).
|
||||||
|
* - `escDelay` — задержка (в миллисекундах) для различения одиночного `Esc` и
|
||||||
|
* escape-последовательностей (стрелки и т.п.). Обычно 0..50 для
|
||||||
|
* отзывчивого UI; слишком маленькое значение может повлиять на
|
||||||
|
* корректность распознавания некоторых клавиш в отдельных терминалах.
|
||||||
*/
|
*/
|
||||||
struct SessionConfig
|
struct SessionConfig
|
||||||
{
|
{
|
||||||
|
|
@ -75,6 +117,10 @@ struct SessionConfig
|
||||||
Cursor cursor = Cursor.normal;
|
Cursor cursor = Cursor.normal;
|
||||||
/// Эхо ввода. По умолчанию отображает вводимые символы (`on`).
|
/// Эхо ввода. По умолчанию отображает вводимые символы (`on`).
|
||||||
Echo echo = Echo.on;
|
Echo echo = Echo.on;
|
||||||
|
/// Обработка специальных клавиш (стрелки, Home/End, PgUp/PgDn, F1..F12 → `KEY_*`).
|
||||||
|
Keypad keypad = Keypad.on;
|
||||||
|
/// Задержка распознавания ESC/escape-последовательностей в миллисекундах.
|
||||||
|
int escDelay = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class Session
|
final class Session
|
||||||
|
|
@ -89,48 +135,79 @@ private:
|
||||||
final switch (config.mode)
|
final switch (config.mode)
|
||||||
{
|
{
|
||||||
case InputMode.raw:
|
case InputMode.raw:
|
||||||
ncuiCall!nocbreak(OK);
|
ncuiNotErr!nocbreak();
|
||||||
ncuiCall!raw(OK);
|
ncuiNotErr!raw();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputMode.cbreak:
|
case InputMode.cbreak:
|
||||||
ncuiCall!noraw(OK);
|
ncuiNotErr!noraw();
|
||||||
ncuiCall!cbreak(OK);
|
ncuiNotErr!cbreak();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputMode.common:
|
case InputMode.cooked:
|
||||||
ncuiCall!noraw(OK);
|
ncuiNotErr!noraw();
|
||||||
ncuiCall!nocbreak(OK);
|
ncuiNotErr!nocbreak();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Настройка отображения вводимых символов.
|
// Настройка отображения вводимых символов.
|
||||||
final switch (config.echo)
|
final switch (config.echo)
|
||||||
{
|
{
|
||||||
case Echo.on:
|
case Echo.on:
|
||||||
ncuiCall!echo(OK);
|
ncuiNotErr!echo();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Echo.off:
|
case Echo.off:
|
||||||
ncuiCall!noecho(OK);
|
ncuiNotErr!noecho();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Настройка видимости курсора.
|
||||||
|
ncuiNotErr!curs_set(config.cursor);
|
||||||
|
// Настройка задержки при нажатии на ESC
|
||||||
|
ncuiNotErr!set_escdelay(config.escDelay);
|
||||||
|
// Настройка обработки специальных клавиш
|
||||||
|
ncuiNotErr!keypad(_root, config.keypad);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
this(const SessionConfig config)
|
this(const SessionConfig config)
|
||||||
{
|
{
|
||||||
|
// ncurses не должен быть инициализирован (false)
|
||||||
|
ncuiExpectMsg!cursesInitialized("ncurses is already initialized", false);
|
||||||
// Адекватное чтение юникода.
|
// Адекватное чтение юникода.
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
_root = NCWin(ncuiNotNull!initscr());
|
_root = NCWin(ncuiNotNull!initscr());
|
||||||
|
|
||||||
|
// Если на этапе инициализации сработает проблема с конфигурированием сессии
|
||||||
|
scope (failure)
|
||||||
|
{
|
||||||
|
endwin();
|
||||||
|
gInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Установить флаг инициализации ncurses
|
||||||
|
gInitialized = true;
|
||||||
setup(config);
|
setup(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NCWin root()
|
||||||
|
{
|
||||||
|
return _root;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyEvent readKey(NCWin inputWindow)
|
||||||
|
{
|
||||||
|
dchar ch;
|
||||||
|
int status = wget_wch(inputWindow, &ch);
|
||||||
|
return KeyEvent(status, ch);
|
||||||
|
}
|
||||||
|
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
if (_ended)
|
if (_ended)
|
||||||
return;
|
return;
|
||||||
endwin();
|
endwin();
|
||||||
_ended = true;
|
_ended = true;
|
||||||
|
gInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
~this()
|
~this()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue