Как получить одно нажатие клавиши в D2 (Фобос)?

Есть ли простой кроссплатформенный способ получить одно нажатие клавиши в D2 с помощью Phobos?

Например, приглашение «Нажмите любую клавишу, чтобы продолжить…» или интерпретатор Brainfuck.

Все методы, которые я пробовал, требуют нажатия клавиши Enter перед передачей ввода (например, getchar()).


person bfops    schedule 21.03.2011    source источник
comment
Пожалуйста, будьте более конкретными. Д1 или Д2? Фобос или Танго?   -  person dsimcha    schedule 21.03.2011
comment
В C функция getch из нестандартного заголовка conio.h делает то, что вы хотите. Однако из того, что я могу сказать, этого нет в D's std.c.*. Я буду искать.   -  person jgottula    schedule 21.03.2011
comment
В этой ветке есть важная информация: digitalmars.com/d/archives /digitalmars/D/обучение/   -  person jgottula    schedule 21.03.2011
comment
Я просто делаю Press ENTER to continue... и с этим покончено. :\   -  person user541686    schedule 22.03.2011


Ответы (2)


Я провел некоторое исследование по этому вопросу и обнаружил, что хотя в библиотеке Phobos для D 1.0 было именно то, что вам нужно, в виде std.c.stdio.getch(), в D 2.0 эта функция отсутствует. Ни одна из других стандартных функций ввода в Phobos не имеет нужного вам поведения.

Насколько я понимаю, это связано с тем, что желаемое поведение (то есть получение одного символа без необходимости нажатия клавиши Enter) довольно нестандартно и должно быть реализовано относительно уродливыми, специфичными для платформы способами. (В своей первоначальной форме функция getch существовала в языке C <conio.h>, специфичном для DOS заголовок, который стал своего рода кросс-платформенным стандартом де-факто, несмотря на то, что он не является частью стандартной библиотеки C.) Очевидно, разработчики библиотеки времени выполнения Phobos решили убрать эту конкретную часть обратно совместимой функциональности во имя очистки библиотеку, но за счет этого функционала.

Ручное объявление

По сообщениям, вы можете обойти это отсутствующее объявление функции, добавив это в исходный файл:

extern (C) int getch();

Однако я обнаружил, что это приводит к ошибке компоновщика, предполагая, что функция была полностью удалена из библиотеки времени выполнения, а не просто удалена ее объявление из std.c.stdio. Это, безусловно, стоит попробовать — может случиться так, что это сработает в вашей системе и компиляторе, я действительно не знаю.

Редактировать 2: похоже, что это действительно работает в Windows; это не удалось для меня на стороне Linux. Похоже, что DMD под Windows сначала ссылается на среду выполнения Phobos/D (phobos.lib), а затем на среду выполнения C (snn.lib); однако в Linux DMD ссылается на одну библиотеку времени выполнения, которая содержит обе части. Это различие, по-видимому, приводит к тому, что привязка к необъявленным функциям (среди них getch) работает только в Windows. Если вас интересует только Windows, это решение, вероятно, подойдет. Если вам нужно больше кроссплатформенной совместимости, читайте дальше.

ругает

Другая возможность — использовать библиотеку ncurses. Он реализует функцию getch, которая определенно сделает то, что вы хотите, при условии, что вы круто с поиском привязок D для библиотеки или просто с использованием интерфейса C. Имейте в виду, что для этого требуется чуть больше настройки, чем просто вызов нужной функции; эта ветка содержит дополнительную информацию по этому вопросу.

D 1.0

Теперь о некоторых значительно более уродливых решениях. Использование D 1.0 позволит вам найти то, что вам нужно, в стандартной библиотеке Phobos, но это, очевидно, влечет за собой использование более старой, более жесткой версии языка, и лично я не считаю отсутствие одной консольной функции ввода-вывода в стандартной библиотеке оправданием. за использование старой версии D.

Я считаю, что Tango также потерял свою декларацию getch (под tango.stdc.stdio) при переходе на D 2.0, но мои знания о Tango крайне ограничены, поэтому я могу ошибаться.

Напиши это сам

Если вы полны решимости, вы можете просто написать свой собственный getch. Мне не удалось найти кроссплатформенную реализацию getch на C с помощью поиска Google Code, что оставляет меня пессимистичным в отношении вероятности относительно простой реализации функции из 10 строк или около того, которую можно было бы просто адаптировать к D.

С другой стороны, Уолтер Брайт — вы знаете, парень, разработавший язык D, — обеспечивает реализацию D именно такой функции здесь. Однако даже это кажется несколько устаревшим, потому что один из символов, cfmakeraw, не определен в текущей версии компилятора DMD2. Тем не менее, это действительно близко к рабочему решению.

person jgottula    schedule 21.03.2011
comment
Дополнение к разделу Ручное объявление: возможно, вы сможете добавить это объявление функции в свой код, а затем связать его с библиотекой среды выполнения Digital Mars C++, которая, насколько мне известно, определяет getch . Вероятно, это не сработает, но стоит упомянуть. Еще одно хакерское решение наверняка. - person jgottula; 22.03.2011

Самое простое решение, которое работает с D2 в Windows:

import std.stdio : writefln;

extern(C) int kbhit();
extern(C) int getch();

void main()
{
    while(!kbhit())
    {
        // keep polling
        // might use Thread.Sleep here to avoid taxing the cpu.
    }

    writefln("Key hit was %s.", cast(char)getch());
}

Это может даже работать с D1, но я не пробовал.

Вот версия для Linux, измененная с Пост Уолтера:

import std.stdio : writefln;
import std.c.stdio;
import std.c.linux.termios;

extern(C) void cfmakeraw(termios *termios_p);

void main() 
{
    termios  ostate;                 /* saved tty state */
    termios  nstate;                 /* values for editor mode */

       // Open stdin in raw mode
       /* Adjust output channel        */
    tcgetattr(1, &ostate);                       /* save old state */
    tcgetattr(1, &nstate);                       /* get base of new state */
    cfmakeraw(&nstate);
    tcsetattr(1, TCSADRAIN, &nstate);      /* set mode */

      // Read characters in raw mode
    writefln("The key hit is %s", cast(char)fgetc(stdin));

       // Close
    tcsetattr(1, TCSADRAIN, &ostate);       // return to original mode
}
person Andrej Mitrović    schedule 21.03.2011
comment
Вы пытались скомпилировать это в своей системе? В моей системе (компилятор DMD2) я получаю ошибки компоновщика для kbhit и getch. Я полагаю, что они были удалены из библиотеки времени выполнения (подробности см. В моем ответе) — или это может быть просто моя версия компилятора, я не могу говорить о версии для Windows. - person jgottula; 22.03.2011
comment
@jgottula Я использую DMD 2.052. kbhit и getch определены в snn.lib, которая, если я не ошибаюсь, является специфичной для компилятора библиотекой (?). GDC также компилирует этот пример. - person Andrej Mitrović; 22.03.2011
comment
Я на Linux x86_64 с DMD 2.049 (немного отстает от текущей 2.052). Я посмотрю, существует ли что-нибудь похожее на snn.lib на стороне Linux. Возможно, это различие библиотек для конкретной платформы (это неудивительно, учитывая, что kbhit и getch не объявлены в пространстве имен стандартной библиотеки). - person jgottula; 22.03.2011
comment
snn.lib является библиотекой среды выполнения Digital Mars C (см. digitalmars. com/d/2.0/dmd-windows.html#linking). К сожалению, на соответствующей странице Linux ничего не говорится о том, какие библиотеки есть какие. - person jgottula; 22.03.2011
comment
Теперь я нашел кое-что говорящее: на стороне Windows компоновщик сначала ссылается на phobos.lib (среда выполнения D), а затем ссылается на snn.lib (среда выполнения C). Но в Linux все содержится в libphobos2.a (сравните каталог linux/lib32 с каталогом windows/lib в zip-файле DMD). Таким образом, очевидно, что на разных платформах все работает принципиально по-разному, в результате чего ссылки на функции C в библиотеке времени выполнения могут не всегда работать в Linux/Posix. :С - person jgottula; 22.03.2011
comment
@jgottula: я отредактировал свой пост с Linux-решением проблемы OP, если вы не заметили. Я успешно скомпилировал и использовал его в недавней установке Ubuntu. - person Andrej Mitrović; 22.03.2011
comment
Это аккуратно! Что вы изменили, чтобы устранить ошибку компоновщика, которую я получил с решением Уолтера? - person jgottula; 22.03.2011
comment
Я добавил прототип cfmakeraw. Я просто сделал быстрый поиск в Google и нашел его прототип на вики-сайте и немного изменил его для использования с D. - person Andrej Mitrović; 22.03.2011