2013-07-01 150 views
4

我正在使用Java創建自定義外殼程序。我已經加入歷史上它,這樣當按下向上箭頭它轉到前面的命令,但向上箭頭似乎沒有工作將歷史記錄添加到自定義外殼程序

這裏是我的代碼:

public class MyShell { 

    public static class JavaStringHistory 
    { 
     private List<String> history = new ArrayList<String>(); 
    } 

    public static void main(String[] args) throws java.io.IOException { 
     JavaStringHistory javaStringHistory = new JavaStringHistory(); 
     javaStringHistory.history.add(""); 

     Integer indexOfHistory = 0; 

     String commandLine; 
     BufferedReader console = new BufferedReader 
       (new InputStreamReader(System.in)); 


     //Break with Ctrl+C 
     while (true) { 
      //read the command 
      System.out.print("Shell>"); 
      commandLine = console.readLine(); 
      javaStringHistory.history.add(commandLine); 

      //if just a return, loop 
      if (commandLine.equals("")) 
       continue; 
      //history 

      if (commandLine.equals(KeyEvent.VK_UP)) 
      { 
       System.out.println("up arrow"); 
      } 
      //help command 
      if (commandLine.equals("help")) 
      { 
       System.out.println(); 
       System.out.println(); 
       System.out.println("Welcome to the shell"); 
       System.out.println("Written by: Alex Frieden"); 
       System.out.println("--------------------"); 
       System.out.println(); 
       System.out.println("Commands to use:"); 
       System.out.println("1) cat"); 
       System.out.println("2) exit"); 
       System.out.println("3) clear"); 
       System.out.println(); 
       System.out.println(); 
       System.out.println("---------------------"); 
       System.out.println(); 
      } 

      if (commandLine.equals("clear")) 
      { 

       for(int cls = 0; cls < 10; cls++) 
       { 
        System.out.println(); 
       } 


      } 

      if(commandLine.startsWith("cat")) 
      { 
       System.out.println("test"); 
       //ProcessBuilder pb = new ProcessBuilder(); 
       //pb = new ProcessBuilder(commandLine); 
      } 

      else 
      { 
       System.out.println("Incorrect Command"); 
      } 


      if (commandLine.equals("exit")) 
      { 

       System.out.println("...Terminating the Virtual Machine"); 
       System.out.println("...Done"); 
       System.out.println("Please Close manually with Options > Close"); 
       System.exit(0); 
      } 

      indexOfHistory++; 

     } 
    } 
} 

所有我得到的是

Shell>^[[A 
Incorrect Command 
Shell> 

有什麼想法?

+0

恕我直言,你應該切換到一個基於Swing的控制檯,在的KeyEvents完全控制是可能的,沒有任何platf orm依賴。否則,可能會找到一個解決方案,但將是本地的或結束使用第三方API。那麼,這不是一個答案,而只是一個建議。順便說一句,我猜你還沒有嘗試過你的程序在Windows機器上(DOS)。這是最好的提供完美的歷史。 – blackSmith

回答

6

有幾個問題你的方法:

  • 用戶鐵匠我之前已經提到,系統控制檯處理是與平臺相關的當涉及到光標鍵處理和類似的主題。
  • BufferedReader.readLine在shell中用於歷史循環不是一個明智的選擇,因爲您希望shell立即對光標鍵作出反應並且不會強制用戶按Return或Enter。只有用戶命令才需要讀取整行。因此,你需要掃描每個單個字符或鍵碼的鍵盤輸入,並自己決定它是否是例如光標鍵(歷史循環上/下,命令行內光標移動的左/右)或用於命令行編輯的刪除/退格等等。
  • 通過讀取控制字符readLine創建的文本字符串可能依賴於操作系統,甚至可能依賴於控制檯上的shell和字符集(UTF-8,ISO-8859-1,US ASCII等)。
  • 內置shell編輯功能(如命令歷史記錄)可能會妨礙readLine,在Linux上,我看到「^ [[A]光標向上的東西,在Windows上光標鍵被傳遞到cmd.exe的內置命令歷史記錄功能。即您需要將控制檯放在原始模式下(線路編輯繞過並且不需要Enter鍵),而不是烹飪模式(需要使用Enter鍵進行線路編輯)。

無論如何,爲了回答你最初的問題,關於如何找出由BufferedReader.readLine產生哪些鍵碼,它實際上很簡單。只是轉儲字節到控制檯,像這樣:

commandLine = console.readLine(); 
System.out.println("Entered command text: " + commandLine); 
System.out.print ("Entered command bytes: "); 
for (byte b : commandLine.getBytes()) 
    System.out.print(b + ", "); 
System.out.println(); 

在Linux下光標可能是這樣的「27,91,65」或只是「91,65」,根據不同的終端上。光標向下以「66」結束,而不是在我的系統上。所以,你可以這樣做:

public class MyShell { 
    private static final String UP_ARROW_1 = new String(new byte[] {91, 65}); 
    private static final String UP_ARROW_2 = new String(new byte[] {27, 91, 65}); 
    private static final String DN_ARROW_1 = new String(new byte[] {91, 66}); 
    private static final String DN_ARROW_2 = new String(new byte[] {27, 91, 66}); 

    // (...) 

    public static void main(String[] args) throws IOException { 
     // (...) 
      // history 
      else if (commandLine.startsWith(UP_ARROW_1) || commandLine.startsWith(UP_ARROW_2)) { 
       System.out.println("up arrow"); 
      } 
      else if (commandLine.startsWith(DN_ARROW_1) || commandLine.startsWith(DN_ARROW_2)) { 
       System.out.println("down arrow"); 
      } 
     // (...) 
    } 
} 

但是,這一切都只是爲了說明或示範,以便回答你的問題 - 我不喜歡拿到賞金。 ;-)

也許很長的路要走是不是要重新發明輪子和利用他人,例如工作像JLine這樣的框架。從我所聽到的內容來看,這並不完美,但要遠遠超過您在短時間內自行開發的任何事情。有人寫了關於JLine的簡短介紹blog post。圖書館似乎只是做你需要的。請享用!


更新:我給JLine 2.11小試與此代碼示例(基本上是一個從博客文章加上標籤文件名完成:

import java.io.IOException; 

import jline.TerminalFactory; 
import jline.console.ConsoleReader; 
import jline.console.completer.FileNameCompleter; 

public class MyJLineShell { 
    public static void main(String[] args) { 
     try { 
      ConsoleReader console = new ConsoleReader(); 
      console.addCompleter(new FileNameCompleter()); 
      console.setPrompt("prompt> "); 
      String line = null; 
      while ((line = console.readLine()) != null) { 
       console.println(line); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       TerminalFactory.get().restore(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

它可以很好地在Windows和Linux,但我tab完成僅適用於Linux,Windows不支持。總之,命令歷史記錄效果很好兩個平臺上。

2

VK_UP是一個整數常量,而in.readLine()是一個字符串。 他們不會相等。爲什麼不嘗試通過點擊箭頭來測試控制檯中顯示的代碼?因此,像:

if (in.readLine().equals("^[[A"))

,然後你可以清除線,並在最高指數ArrayList中寫的命令。

另外,我測試了這個,發現了一個錯誤。除第一個外,更改您的if聲明至else if;任何命令後,將最終得到的else和顯示「不正確的命令」

+0

嘗試瞭如果(到Console.ReadLine()等於( 「^ [[A」)。) { 的System.out.println( 「向上箭頭」); } 似乎無法識別它。 – Badmiral

+0

儘管使用「\ u001B [A」。 Escape被渲染爲「^ [」,但實際上是一個單獨的,不可打印的字符。 –

相關問題