Ввод с клавиатуры
 

Basic

Используя встроенную функциональность FB, можно выделить четыре способа получения ввода с клавиатуры:

    • Inkey() возвращает строку, содержащую соответствие символа ASCII клавише, нажатой пользователем или 2-байтовый FB расширенный код клавиши для некоторых специальных ключей, таких как клавиши со стрелками или Page Up/Down. Это работает в значительной степени так же , как в QB.
    • Getkey() возвращает те же сведения, как inkey(), но в виде целого числа вместо строки. INKEY() и GETKEY() родственны: они используют тот же код, и они расположены в том же модуле.
    • Multikey() принимает FB scancode (SC_*) и проверяет, является ли эта клавиша нажатой в данный момент.
    • Screenevent() возвращает нажатия клавиш в виде EVENT_KEY_PRESS событий (и других для отпускании клавиши или повторов). Она возвращает FB сканкод в Event.Scancode поле, и значение ASCII символа или 0 в EVENT.ascii поле. EVENT.ascii не использует FB расширенные коды клавиш; поле EVENT.scancode нужно для проверки, а не для того, чтобы справиться с дополнительными клавишами.
"сканкод" относится к SC_* объявлениям, которые более или менее соответствуют клавиатуре DOS сканкодов. Значения не составлены, они сами соответствуют определенным символам ASCII, например: SC_HOME = asc( "G" ) = &h47. Это те же значения, которые Вы получаете под DOS/DJGPP или от ядра Linux как часть расширенных последовательностей кода клавиши. Помимо их использования в multikey() или screenevent(), сканкоды используются в различных местах внутренне, например при переводе между различными видами кодов клавиши, как простое в использовании и переносимое представление кодов клавиши.

"ключ" относится к символу ASCII, или к 2-байтовой расширенной строке KeyCode для других ключей, возвращаемого INKEY (). У rtlib есть несколько KEY_* объявлений для доступных 2-байтовых расширенных кодов клавиш, в виде целых чисел. Они используются внутренне и также соответствуют значениям, возвращенных getkey ().

2 байта расширенных кодов клавиш FB состоят из &hFF байта, сопровождаемого байтом, содержащим SC_* сканкод значение, соответствующее нажатию клавиши. Проверка SC_HOME, возвращенный inkey (), могла быть похожей:

if( inkey( ) = chr( 255 ) + "G" ) then ...
Проверка на SC_HOME возвращаемого GetKey ():
if( getkey() = &h47FF ) then ...
if( getkey() = ((SC_HOME shl 8) or &hFF) ) then ...
inkey(), getkey() и multikey() используют обертки функций, которые вызывают ...
    • версии консольного режима fb_ConsoleInkey(), fb_ConsoleGetkey(), fb_ConsoleMultikey() по умолчанию,
    • или же gfxlib версии fb_GfxInkey(), fb_GfxGetkey(), fb_GfxMultikey() если графический SCREEN активный,
при помощи хуков.

rtlib

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

  • DOS
fb_ConsoleInkey() и fb_ConsoleGetkey() используют DJGPP's getch()функцию для извлечения вводимых символов в любое время их вызова. getch() возвращает ASCII символы, но также и 2 упорядоченных байта для специальных ключей, которые легко обработать, потому что они соответствуют SC_* сканкодам.
fb_ConsoleMultikey() устанавливает обработчик прерывания, который использует порты ввода/вывода для считывания информации с клавиатуры и обновляет ключевую таблицу состояний, которая проверяется MultiKey ().
  • Win32
fb_ConsoleInkey() и fb_ConsoleGetkey() (косвенно) используют функции Win32 API  PeekConsoleInput() и ReadConsoleInput() чтобы получить поставленное в очередь событие нажатия/отпускания клавиши каждый раз при возникновении такой необходимости. Все неоконченные события в настоящее время обрабатываются во время вызова, и после очень сложного внутреннего перевода включений MapVirtualKey(),ключи помещаются в буфер, откуда fb_ConsoleInkey() и fb_ConsoleGetkey() читают ключи и возвращают.

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

fb_ConsoleMultikey() использует FindWindow()/GetForegroundWindow() для хука, чтобы определить,под фокусом ли окно консоли, и если да, просто использует GetAsyncKeyState().
  • Linux, *BSD
Порт Unix rtlib запускает консольный обработчик клавиатуры (и консольный обработчик мыши) в фоновом потоке, чтобы обеспечить ввод для multikey() (и getmouse()).

fb_ConsoleInkey() и fb_ConsoleGetkey () читают входные байты __ fb_con.keyboard_getch () хука. По умолчанию, __ fb_con.keyboard_getch() указывает на простую функцию, которая просто использует fgetc() на /dev/tty (косвенно; Unix rtlib код инициализации открывает дескриптор и изменяет настройки ввода-вывода и т.д., не только в целях ввода с клавиатуры, но и в основном).

Терминал возвращает символы ASCII для простых нажатий клавиш и специальные escape-последовательности для расширенных ключей. При первом вызове различные termcap lookups (через tgetstr()) делаются, чтобы определить эти терминально-специфичные escape-последовательности для определенных событий нажатия клавиши, и поместить в дерево поиска, чтобы обеспечить простой быстрый перевод в расширенные коды клавиш соответствующего FB. Делая termcap запрос Unix rtlib, можно поддерживать все различные терминалы (например, xterm vs. Linux) вполне хорошо, несмотря на то, что все еще есть некоторые ключи, не работающие то там , то тут.

Только одно "событие" (символ ASCII или escape-последовательность) считывается за один раз, получающийся ключ добавляется в буфер ключей, откуда fb_ConsoleInkey() и fb_ConsoleGetkey() могут считать его.

fb_ConsoleMultikey() в настоящее время реализован для порта Linux только, не под *BSD. В консольном режиме ввода (используемый под 'console'/'linux' терминалом), дескриптор  dup()licates /dev/tty rtlib переключается в средний режим без предварительной обработки. Тогда это переопределяет фоновый поток __fb_con.keyboard_handler()хучя функцию read() кодов клавиш ядра из дублированного дескриптора /dev/tty.
Вызванный из фонового потока, он читает фиксированное количество ввода сразу, каждый раз, когда это прибывает. После довольно сложного перевода , таблица ключей обновляется, чтобы отразить состояние нажатых / отжатых кнопок, чтобы потом быть проверенной fb_ConsoleMultikey(). Ключи добавляются в буфер ключей и оттуда переопределенная __ fb_con.keyboard_getch () читает их, каждый раз, когда вызывается fb_ConsoleInkey() или fb_ConsoleGetkey() [почему это сделано?]. Кроме того, ключи отправляются в драйвер Linux fbdev gfxlib2, если это активно.
В режиме X11 (используя под 'xterm' терминалом), fb_ConsoleMultikey () устанавливает фоновый поток __ fb_con.keyboard_handler() который проверяет, есть ли у xterm фокус ввода (XGetInputFocus ()) и если есть, просто XQueryKeymap() используется, чтобы обновить таблицу ключей для fb_ConsoleMultikey ().
gfxlib2

В gfxlib fb_GfxInkey () и fb_GfxGetkey () используют один ключевой буфер (код всех платформ), в который различные/платформо-специфичные gfx драйверы отправляют ключи. Подобно этому, есть единственная таблица ключей для fb_GfxMultikey (), и это также обновляется gfx драйверами. Отправляют ли gfx драйверы фактически ключи или обновляют ключевые состояния, это уже дело драйверов.

  • DOS
Порт DOS gfxlib2 (для всех DOS gfx драйверов) устанавливает хук/обратный вызов, это вызывает тот же обработчик прерываний клавиатуры, используемый DOS fb_ConsoleMultikey ().
  • Win32 driver
Поток gfx окна читает сообщения WM_KEYDOWN, WM_CHAR и WM_CLOSE, переводит ключи, и затем обновляет таблицу ключей, отправляет их в буфер fb_GfxInkey ()/fb_GfxGetkey() и отправляет соответствующее EVENT(событие) для screenevent ().
  • X11 driver
Поток gfx окна читает KeyPress и другие XEvent события, переводит ключи, затем отправляет их , точно так же, как драйвер Win32.
  • Linux fbdev driver
Как упоминалось выше, драйвер FBdev получает свой ввод из того же кода обработчика клавиатуры, который используется в Linux fb_ConsoleMultikey().