捕获一个字符,但在 C 程序中显示其他内容

问题描述

是否可以编写一个等待用户输入的 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。

更多关于诅咒 heregetch() here

,

由于您使用的是 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 存储在数组中来保存实际输入。