教程 2
在第二个教程中,我们将扩展如何使用终端界面来提供更高级的功能。
DefaultTerminalFactory defaultTerminalFactory = new DefaultTerminalFactory();
Terminal terminal = null;
try {
terminal = defaultTerminalFactory.createTerminal();
大多数终端和终端仿真器都支持所谓的“私有模式”,它是不支持任何滚动的文本内容的单独缓冲区。这经常被文本编辑器使用,例如nano 为了vi提供“全屏”视图。退出私密模式时,通常会恢复之前的内容,包括回滚历史。不支持此功能的模拟器至少可以在退出后清除屏幕。
terminal.enterPrivateMode();
您可以使用enterPrivateMode()激活私人模式,但您需要记住之后还要退出私人模式,以免在应用程序存在时使终端处于奇怪的状态。通常close()最后会自动执行此操作,但您也可以手动调用exitPrivateMode() ,最后 Lanterna 将注册一个关闭挂钩,尝试恢复终端(包括退出私人模式,如果需要)。
切换到隐私模式后终端内容应该已经被清除,但如果没有, clear 方法应该将所有内容设置为默认背景色,没有字符,输入光标在左上角。
terminal.clearScreen();
可以告诉终端隐藏文本输入光标
terminal.setCursorVisible(false);
与我们在上一个教程中所做的那样一次手动写入一个字符不同,更简单的方法是使用 TextGraphic 对象。稍后您会看到更多这个对象,它也被重用在 Screen 和 TextGUI 层上。
final TextGraphics textGraphics = terminal.newTextGraphics();
TextGraphics 对象保持自己的当前颜色状态,与终端分开。您可以使用前台和后台设置方法来指定它,它将对所有操作生效,直到进一步修改。
textGraphics.setForegroundColor(TextColor.ANSI.WHITE);
textGraphics.setBackgroundColor(TextColor.ANSI.BLACK);
putString(..)存在几种不同的风格,但它通常通过获取一个字符串并将其输出到终端窗口的某个位置来工作。请注意,执行此操作时它不会占用文本光标的当前位置。
textGraphics.putString(2, 1, "Lanterna Tutorial 2 - Press ESC to exit", SGR.BOLD);
textGraphics.setForegroundColor(TextColor.ANSI.DEFAULT);
textGraphics.setBackgroundColor(TextColor.ANSI.DEFAULT);
textGraphics.putString(5, 3, "Terminal Size: ", SGR.BOLD);
textGraphics.putString(5 + "Terminal Size: ".length(), 3, terminal.getTerminalSize().toString());
您仍然需要刷新才能使更改可见
terminal.flush();
您可以将调整大小侦听器附加到您的Terminal对象,当通知终端模拟器窗口更改大小时,它将调用回调方法(通常在单独的线程上)。请注意,可能并非所有实现都支持这一点。UnixTerminal例如, 依赖于发送到 java 进程的信号WINCH,如果您的远程 shell 没有正确转发信号,这可能不会成功。
terminal.addResizeListener(new TerminalResizeListener() {
@Override
public void onResized(Terminal terminal, TerminalSize newSize) {
// Be careful here though, this is likely running on a separate thread. Lanterna is threadsafe in
// a best-effort way so while it shouldn't blow up if you call terminal methods on multiple threads,
// it might have unexpected behavior if you don't do any external synchronization
textGraphics.drawLine(5, 3, newSize.getColumns() - 1, 3, ' ');
textGraphics.putString(5, 3, "Terminal Size: ", SGR.BOLD);
textGraphics.putString(5 + "Terminal Size: ".length(), 3, newSize.toString());
try {
terminal.flush();
}
catch(IOException e) {
// Not much we can do here
throw new RuntimeException(e);
}
}
});
textGraphics.putString(5, 4, "Last Keystroke: ", SGR.BOLD);
textGraphics.putString(5 + "Last Keystroke: ".length(), 4, "<Pending>");
terminal.flush();
现在让我们尝试读取一些输入。有两种方法,pollInput()和readInput()。一个是阻塞的(readInput),一个不是(pollInput),如果没有可读取的内容,则返回 null。
KeyStroke keyStroke = terminal.readInput();
KeyStroke 类有几个不同的方法来获取有关读取的特定输入的详细信息。请注意,某些键(如 CTRL 和 ALT)无法单独区分,因为标准输入流不会将它们报告为单独的键。一般特殊键都用special 分类 KeyType,而普通的字母数字键和符号键都在 下KeyType.Character。请注意,不考虑 tab 和 enterKeyType.Character而是特殊类型(KeyType.Tab和KeyType.Enter分别)
while(keyStroke.getKeyType() != KeyType.Escape) {
textGraphics.drawLine(5, 4, terminal.getTerminalSize().getColumns() - 1, 4, ' ');
textGraphics.putString(5, 4, "Last Keystroke: ", SGR.BOLD);
textGraphics.putString(5 + "Last Keystroke: ".length(), 4, keyStroke.toString());
terminal.flush();
keyStroke = terminal.readInput();
}
}
catch(IOException e) {
e.printStackTrace();
}
finally {
if(terminal != null) {
try {
此处的 close() 调用将退出私有模式
terminal.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
本教程的完整代码可在源代码的测试部分中找到