Признавая клавиши со стрелками с stdin

возможно ли иметь кросс-платформенный способ обработки backspace и клавиш со стрелками в программе C или OCaml?

на самом деле решение OCaml было бы оценено, но многие стандартные функции unix обернуты непосредственно к соответствующим вызовам API, поэтому не должно быть никаких проблем в переносе решения C.

то, что я собираюсь достичь, это поймать клавиши со стрелками, чтобы переопределить его поведение внутри оболочки (путем перепробования последней строки или таких операций). Я думаю что эта вещь падает перед фактической программой, и она не обрабатывается самим кодом, поэтому я не знаю, возможно ли это.

программа компилируется либо на Linux, OS X и Windows (на cygwin), поэтому я хотел бы сделать это для всех платформ..

4 ответов


недавно я сделал что-то похожее (хотя мой код-только Linux). Вы должны установить stdin в неканонический режим, чтобы прочитать нажатия клавиш со стрелками. Это должно работать на OS X и Linux и, вероятно, будет работать на Cygwin, хотя я не могу сказать наверняка.

open Unix
let terminfo = tcgetattr stdin in
  let newterminfo = {terminfo with c_icanon = false; c_vmin = 0; c_vtime = 0} in
    at_exit (fun _ -> tcsetattr tsdin TCSAFLUSH terminfo); (* reset stdin when you quit*)
    tcsetattr stdin TCSAFLUSH newterminfo;

когда канонический режим выключен, вам не нужно ждать новой строки для чтения из stdin. c_vmin представляет минимальное количество символов для чтения перед возвратом (вероятно, вы хотите иметь возможность для чтения одного символа за раз) и c_vtime-максимальное время ожидания чтения (в единицах 0,1 с).

вы также можете установить c_echo false, чтобы клавиши со стрелками печатаются в терминале (но тогда вам придется вручную печатать все остальное.

большинство терминалов представляют клавиши со стрелками с помощью ANSI escape-последовательности. Если вы бежите cat без аргументов и начать нажимать клавиши со стрелками вы можете увидеть escape-последовательности, используемые. Они обычно

up - "7[A"
down - "7[B"
left - "7[D"
right - "7[C"

где '\027 ' - значение ascii для esc


используйте ncurses для извлечения последовательностей для возможностей клавиши со стрелкой, а затем ищите их при чтении stdin. Это, наверное, проще использовать что-то вроде libedit или вместо readline и пусть это дело с keyhandling.


стандартный способ поддержки ввода с клавиатуры за пределами строк печатаемых символов - через ncurses библиотека, которая имеет данные, используемые переплетные. Еще одна распространенная возможность -readline библиотека (наиболее широко используется Bash).

Если все, что вы делаете, это чтение ввода строка за строкой, но хотите, чтобы ваши пользователи имели достойный редактор строк, нет необходимости включать какую-либо поддержку в вашу программу. Вместо этого просто скажите своим пользователям использовать программа-оболочка, такая как rlwrap (который основан на readline) или прикольно. Эти обертки предоставляют line edition и историю, две функции, которые вы перечисляете в качестве своих требований. Я бы рекомендовал вам построить обработку ввода в вашу программу, только если вы хотите что-то более причудливое, например, завершение программы, когда пользователь нажимает Tab.


Backspace является символом ASCII и будет помещен в stdin, как и любой другой символ. Символ escape-последовательности '\b' является символом backspace.

для клавиш курсора они не связаны с каким-либо управляющим символом, поэтому не генерируйте данные в потоке stdin. Низкий уровень доступа обязательно зависит от платформы, хотя существуют кросс-платформенные библиотеки, которые абстрагируются от различий платформы. Я считаю, что ncurses доступен для всех платформ, которые вы упомянутый.