2013-02-27 2 views
0

Я занимаюсь разработкой командной оболочки с использованием Java. Одной из важных функций, которые я должен был немедленно реализовать, была «автоматическая комплектация», что облегчалось командной оболочкой при нажатии клавиши «tab». Для этого я считал, что мне нужно прочитать команду ввода, по-символу в режиме без блокировки.Неблокирующий вход в Java, реализованный через JNI

К сожалению, как я понял, ни один из поддерживающих Java API неблокирующий вход. То есть Java API, предназначенные для чтения входных ожиданий (блоков), пока пользователь не нажмет клавишу «Enter», что очень нежелательно в моем случае. Также я решил не использовать сторонние библиотеки Java (Таких как JLine).

Итак, мне пришлось прибегнуть к JNI. Родной файл .C, как представляется, это -

JNIEXPORT jint JNICALL Java_autoComplete_IOUtils_read_1character(JNIEnv *env, jobject obj) 
{ 

int ch = getch(); // getch() - non-blocking input and doesn't echo the characters 
return (jint)ch; 
} 

и соответствующий метод Java, в котором вышеупомянутый нативный метод вызывается:

public static String GetLine() 
{ 

    int i = 0; 
    do 
    { 
     char variable = (char) read_character(); // Native method is invoked here 

     System.out.println(variable); // Just printing it for my reference 

     cmdLine = new StringBuffer(cmdLine).insert(i, variable).toString(); // cmdLine is of type String 
     i++; 

    } while ((search(cmdLine.charAt(i - 1), interruptableCharacterArray)) == false); 

    return (new String(cmdLine)); 

} 

//Checks if the entered character is any one of those keys in the interruptableCharacterArray . As of now , interruptableCharacterArray contains only '\t' (The tab key) 


    private static boolean search(char charAt,char[] interruptableCharacterArray2) 
{ 
    for (int i = 0; i < index; i++) 
    { 
     if (interruptableCharacterArray2[i] == charAt) 
      return true; 
    } 
    return false; 
} 

Кроме того, я могу заверить вас, что нет никаких неприятностей в отношении связывания родного .dll. И, «InterruptableCharacterArray», на данный момент содержит только «\ t» (клавиша «tab»). Следовательно, значение индекса на данный момент равно 1.

Probelm:

1> Контроль не кажется, чтобы блокировать по адресу:

char variable = (char) read_character(); 

То есть, это, кажется, не позволяет пользователю ввести вход через Java Консоль на этой линии, которая предназначена для этого. И это также проблема даже в случае getche() (Non-blocking, но эхо)

Вместо этого на каждой итерации берется значение по умолчанию для «переменной», которое печатается на консоли, когда следующее утверждение выполняется:

System.out.println(variable); 

Однако этот код шахты работает как шарм, когда Геч() заменяется ее блокирующих аналогами как ЕОКП (стандартный ввод), GetChar() и т.д..

Я не могу понять, что именно является проблемой при вызове getch() через JNI.

2> Кроме того, я был бы признателен, если бы предложили другие альтернативные решения для достижения того же.

Заранее благодарю вас!

Редактировать: Командная оболочка должна быть реализована как на ОС Windows, так и на основе Unix.

+0

То, что вы хотите, не «неблокирующим» IO, но «сырой» выходовспомощьютерминал. Я предлагаю вам посмотреть на вещи, такие как stty – Ingo

+0

@Ingo: Большое спасибо! Что относительно Windows O/S? – bsv0099

+0

Обратите внимание на ссылки, которые Аарон опубликовал. JLine2 явно обрабатывает терминалы Windows, поэтому вы можете получить идеи там. BTW, чтобы стать хорошей средой переполнения стека, вы должны проголосовать за полезные ответы и принять лучшее. Я думаю, что должность Аарона заслуживает этого. – Ingo

ответ

1

Прежде чем вы сможете иметь незаблокирующее IO с терминала, вам нужно поместить его в «сырой» режим: терминалы обычно собирают одну строку ввода (таким образом, вы можете редактировать текущую строку с помощью клавиш курсора, и т. д.) и просто отправить его на stdin приложения, когда он «закончен» (= когда пользователь нажимает клавишу ввода).

В режиме «raw» любое нажатие клавиши немедленно отправляется в приложение, и редактирование невозможно (если приложение не реализует его самостоятельно).

Чтобы это сделать, см. Руководство по эксплуатации для stty(1).Чтобы изменить режим, вам понадобится функция C tcsetattr(3).

Я предлагаю заглянуть в source for JLine2, даже если вы не хотите его использовать, в частности, в UnixTerminal.java и TerminalLineSettings

+0

Очень хорошо, но вы ошиблись: в готовом режиме вы не можете редактировать командную строку с помощью клавиш курсора, только с помощью клавиши DEL или Backspace. Это необработанный режим noecho, который позволяет программам осуществлять редактирование с помощью клавиш курсора. – Ingo

+0

@ Инго: Да, вы правы для Unix. Оболочка реализует редактирование, помещая терминал в режим raw/noecho в Unix. На Amiga терминал имел собственные возможности редактирования. Для портирования оболочек unix там мы должны заменить этот код на 'stdin.readline()' :-) –

+0

@AaronDigulla - Спасибо большое! Я бы работал в этом направлении. Кроме того, не могли бы вы рассказать мне, как это сделать в Windows O/S? – bsv0099

Смежные вопросы