问题描述
是否可以编写一个等待用户输入的 C 程序(如 C++ 中的 cin
),并且当用户只按一个键(不输入)时,比如说,“a”字符在键盘终端会显示“b”(仍然等待输入)?如果是这样 - 我怎样才能做到这一点?
解决方法
这是可能的,但这不是“标准”C 所处理的。您需要额外的库来实现这一点。
您需要意识到标准 C(或 C++)函数并不意味着与“键”、“屏幕”或“终端”一起使用。他们唯一能做的就是所谓的“标准输入输出”,仅限于写字符somewhere,以及从somewhere读取字符。字符的来源和目标没有严格定义,取决于附加到 IO 流的内容。
当您考虑按键、屏幕和终端时,您会想到更具体的事情。您对在某些未指定的地方之间发送和接收字符不感兴趣。您希望它们完全来自键,并最终出现在屏幕上。为此,您需要一个知道如何使用按键和屏幕的库。例如,此类库之一是 ncurses
,但可能还有其他替代方案。
有一些与使用附加库相关的潜在问题:可用性、可移植性、可维护性等。当您决定使用哪个库时,您需要考虑这些因素,因为最终选择取决于您的要求:什么平台是你和你一起工作吗?您希望您的代码可移植吗?
,对于 Windows,使用 conio.h
库函数 getch()
,与 Linux 相同,但使用 curses.h
作为示例:
#include <stdio.h>
#include <conio.h> /* or curses if you are on linux*/
int main(void)
{
int c = 0;
c = getch();
if (c == 'a')
{
putchar('b');
getchar(); /* waiting for a newline */
}
return 0;
}
注意 getch()
不是标准的 C 函数。
编辑:正如 Lundin 在评论中指出的,这是一个 MS DOS 实现,而不是我错误标记的 Windows。
,由于您使用的是 Linux 并且不需要存储真实输入,您可以尝试使用 <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
:
termios.h
对于更复杂的事情,请考虑 ncurses
,如果您尝试在用户按下 Enter 之前更改其输入,则需要更改终端的某些配置。 下面的代码将逐个字符读取用户输入的字符并将任何 a 更改为 b。按下回车键后停止。
#include <termios.h>
#include <unistd.h>
int main(void) {
struct termios oldterm,newterm;
tcgetattr(STDIN_FILENO,&oldterm); // save current config
// set new config
newterm = oldterm;
newterm.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
tcsetattr(STDIN_FILENO,TCSAFLUSH,&newterm);
char ch = 0;
while (read(STDIN_FILENO,&ch,1) && ch != '\n') {
if (ch == 'a') // show a's as b's
write(STDOUT_FILENO,"b",1);
else if (ch == 127) // allows deleting chars
write(STDOUT_FILENO,"\b \b",3);
else // other chars
write(STDOUT_FILENO,1);
}
// return to old config
tcsetattr(STDIN_FILENO,TCSANOW,&oldterm);
return 0;
}
您可以通过将读取的字符 ch
存储在数组中来保存实际输入。