我正在开发一种终端程序,以识别各个按键,包括小键盘按键,但我宁愿不要以curses / program模式进行操作。我认为,与其使用terminfo和某种映射或树结构来快速进行键盘按键匹配来重新发明轮子,不如说我可能只是利用curses并使用tcgetattr()
和tcsetattr()
来执行我想在curses模式之外执行的操作仍然使用curses I / O功能为我完成键盘按键的翻译。令我惊讶的是,这行得通(Linux,ncurses 6.1.20180127):
/**
* Most error checking elided for brevity.
*/
#include <stdio.h> // printf
#include <string.h> // memcpy
#include <curses.h>
#include <termios.h> // tcgetattr, tcsetattr
int main(void)
{
struct termios curr, new_shell_mode;
int c, fd;
SCREEN *sp;
FILE *ttyf;
/*
* Initialize desired abilities in curses.
* This unfortunately clears the screen, so
* a refresh() is required, followed by
* endwin().
*/
ttyf = fopen("/dev/tty", "r+b");
fd = fileno(ttyf);
sp = newterm(NULL, ttyf, ttyf);
raw();
noecho();
nonl();
keypad(stdscr, TRUE);
refresh();
// Save the current curses mode TTY attributes for later use.
tcgetattr(fd, &curr);
endwin();
/*
* Set the shell/non-curses mode TTY attributes to
* match those of program/curses mode (3 attempts).
*/
memcpy(&new_shell_mode, &curr, sizeof curr);
for (c = 0; c < 3; c++) {
tcsetattr(fd, TCSADRAIN, &new_shell_mode);
tcgetattr(fd, &curr);
if (0 == memcmp(&new_shell_mode, &curr, sizeof curr))
break;
}
// If new shell mode could fully be set, get a key press.
if (c != 3)
c = getch();
reset_shell_mode();
delscreen(sp);
fclose(ttyf);
printf("%02X\n", c);
return 0;
}
但是,考虑到我已经退出了curses模式,以所示方式仍然使用getch()
真的安全/便携式吗?
还是我需要采取更困难的路径来使用setupterm()
来加载terminfo数据库并遍历strnames
数组,为每个数组调用tigetstr()
,并设置自己的termios手动标记并自己处理读按键?
如果stdscr
仍然有效,那么XSI Curses规范中的任何内容似乎都不禁止这样做,这似乎一直存在,直到程序退出或调用delwin()
为止,我可以继续使用它,并且由于{ {1}}已连接到我的stdscr
文件(该文件为终端文件),我可以使用它来获取按键,而无需自己处理所有事情。
答案 0 :(得分:1)
您使用 newterm
初始化了诅咒,并且您未将 称为 {{1} } :如果curses进行 endwin
作为 refresh
的副作用,它将恢复全屏模式。< / p>
这不仅是ncurses,而且是任何curses实现(除了1980年代早已过时的BSD版本)。 X/Open Curses笔记
如果当前或指定的窗口不是填充板,并且自上次刷新操作以来已被移动或修改,则将在读取另一个字符之前对其进行刷新。
在您的示例中,没有任何内容被“移动或修改”。但是getch
检查。 ( getch
/ termios东西可能无法获得任何东西,因为 endwin
直到第一个< strong> newterm
)。