getch() 确实显示最近输入的字符并跳过输入的所有其他字符
getch() does display most recently typed character and skips every other character entered
正在为 class 完成作业并且已经与 ncurses 斗争了一段时间(这对我来说是新的)。创建一个能够通过网络与同一程序的另一个实例进行通信的程序。该程序的一部分是交互式地从键盘获取字符并将它们发送到接收端。 (我们被建议使用单线程方法并在 ncurses 中使用 getch,并使用来自 getch 的非阻塞输入)。
我 运行 遇到的问题是我的 getch
有我无法弄清楚的行为。在不同的变体中,它会显示我输入的所有其他字符,并且不会显示最近输入的字符,直到在它之后输入另一个字符。我已经使用 nodelay()
来获取实时输入,但是 .
这是我的 ncurses 显示设置。 (注意:我使用 noecho()
因为后来我不想显示输入的每个字符)。
/* initialize ncurses */
setlocale(LC_ALL,"");
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
clear();
这是我编写的代码,可用于 getch
和 sending/receiving 套接字上的数据。
while(1) {
rfdset = master;
if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
ch = getch();
if (ch != ERR) {
printw("%c",ch);
write(direct, &ch, 1); // direction to send data
}
for(i = 0; i <= maxfd; i++) {
if (FD_ISSET(i, &rfdset)) {
bzero(msgbuf, MSGSIZE);
idx = read(i, msgbuf, MSGSIZE);
if (i != STDIN)
printw("%s",msgbuf); // display received msg
}
}
}
当我 运行 在应用程序的任何一端输入数据时,我得到的结果如下:
Computer 1 keyboard input: testing123
Computer 1 screen display: tsig2
Computer 2 message recv'd: tsig2
因此,我确信 getch
是造成我的大部分问题的原因,我一定是在实施过程中遗漏了某些事情或做错了什么。任何建议表示赞赏。
编辑 1:
我设法通过删除 for 循环并直接检查套接字的输入来解决 所有其他字符问题。我很困惑为什么要修复它。现在我唯一剩下的问题是 为什么在输入字符后才显示字符。这是我在 while 循环中修改后的代码:
while(1) {
rfdset = master;
if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
ch = getch();
if (ch != ERR) {
printw("%c",ch);
write(direct, &ch, 1);
}
/* check for incoming data from left socket */
if (!NOLEFT && FD_ISSET(lcsad, &rfdset)) {
bzero(leftmsg, MSGSIZE);
idx = read(lcsad, leftmsg, MSGSIZE);
leftmsg[idx] = 0;
printw("%s", leftmsg);
lm = 1;
}
/* check for incoming data from right socket */
if (!NORIGHT && FD_ISSET(rsd, &rfdset)) {
bzero(rghtmsg, MSGSIZE);
idx = read(rsd, rghtmsg, MSGSIZE);
rghtmsg[idx] = 0;
printw("%s", rghtmsg);
rm = 1;
}
/* check and send left message onward */
if (lm && !NORIGHT) {
write(direct, leftmsg, MSGSIZE);
}
/* check and send right message onward */
if (rm && !NOLEFT) {
write(direct, rghtmsg, MSGSIZE);
}
lm, rm = 0;
}
如果使用 wgetch() 而不是 getch() 可以解决您的问题,您可以试试。
问题在于,因为您的 select
调用没有指定超时(最后一个参数是 NULL
),它会阻塞直到有一些未决的 I/O(例如您键入的下一个字符)。那时,程序继续进入 getch
调用,它执行 refresh
(回显来自 printw
调用的字符)。
指定一个较短的超时时间,例如 10 毫秒,会有所改善,例如,
struct timeval myTimeout;
myTimeout.tv_sec = 0;
myTimeout.tv_usec = 10000;
并在对 select
...
的调用中传递 myTimeout
的地址
正在为 class 完成作业并且已经与 ncurses 斗争了一段时间(这对我来说是新的)。创建一个能够通过网络与同一程序的另一个实例进行通信的程序。该程序的一部分是交互式地从键盘获取字符并将它们发送到接收端。 (我们被建议使用单线程方法并在 ncurses 中使用 getch,并使用来自 getch 的非阻塞输入)。
我 运行 遇到的问题是我的 getch
有我无法弄清楚的行为。在不同的变体中,它会显示我输入的所有其他字符,并且不会显示最近输入的字符,直到在它之后输入另一个字符。我已经使用 nodelay()
来获取实时输入,但是 .
这是我的 ncurses 显示设置。 (注意:我使用 noecho()
因为后来我不想显示输入的每个字符)。
/* initialize ncurses */
setlocale(LC_ALL,"");
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
clear();
这是我编写的代码,可用于 getch
和 sending/receiving 套接字上的数据。
while(1) {
rfdset = master;
if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
ch = getch();
if (ch != ERR) {
printw("%c",ch);
write(direct, &ch, 1); // direction to send data
}
for(i = 0; i <= maxfd; i++) {
if (FD_ISSET(i, &rfdset)) {
bzero(msgbuf, MSGSIZE);
idx = read(i, msgbuf, MSGSIZE);
if (i != STDIN)
printw("%s",msgbuf); // display received msg
}
}
}
当我 运行 在应用程序的任何一端输入数据时,我得到的结果如下:
Computer 1 keyboard input: testing123
Computer 1 screen display: tsig2
Computer 2 message recv'd: tsig2
因此,我确信 getch
是造成我的大部分问题的原因,我一定是在实施过程中遗漏了某些事情或做错了什么。任何建议表示赞赏。
编辑 1:
我设法通过删除 for 循环并直接检查套接字的输入来解决 所有其他字符问题。我很困惑为什么要修复它。现在我唯一剩下的问题是 为什么在输入字符后才显示字符。这是我在 while 循环中修改后的代码:
while(1) {
rfdset = master;
if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
ch = getch();
if (ch != ERR) {
printw("%c",ch);
write(direct, &ch, 1);
}
/* check for incoming data from left socket */
if (!NOLEFT && FD_ISSET(lcsad, &rfdset)) {
bzero(leftmsg, MSGSIZE);
idx = read(lcsad, leftmsg, MSGSIZE);
leftmsg[idx] = 0;
printw("%s", leftmsg);
lm = 1;
}
/* check for incoming data from right socket */
if (!NORIGHT && FD_ISSET(rsd, &rfdset)) {
bzero(rghtmsg, MSGSIZE);
idx = read(rsd, rghtmsg, MSGSIZE);
rghtmsg[idx] = 0;
printw("%s", rghtmsg);
rm = 1;
}
/* check and send left message onward */
if (lm && !NORIGHT) {
write(direct, leftmsg, MSGSIZE);
}
/* check and send right message onward */
if (rm && !NOLEFT) {
write(direct, rghtmsg, MSGSIZE);
}
lm, rm = 0;
}
如果使用 wgetch() 而不是 getch() 可以解决您的问题,您可以试试。
问题在于,因为您的 select
调用没有指定超时(最后一个参数是 NULL
),它会阻塞直到有一些未决的 I/O(例如您键入的下一个字符)。那时,程序继续进入 getch
调用,它执行 refresh
(回显来自 printw
调用的字符)。
指定一个较短的超时时间,例如 10 毫秒,会有所改善,例如,
struct timeval myTimeout;
myTimeout.tv_sec = 0;
myTimeout.tv_usec = 10000;
并在对 select
...
myTimeout
的地址